当前位置: 首页 > news >正文

苍穹外卖Day-5

一、业务代码-修改菜单

第一个接口:根据id查询dish
返回对应的VO

@Data  
@Builder  
@NoArgsConstructor  
@AllArgsConstructor  
public class DishVO implements Serializable {  
  
    private Long id;  
    //菜品名称  
    private String name;  
    //菜品分类id  
    private Long categoryId;  
    //菜品价格  
    private BigDecimal price;  
    //图片  
    private String image;  
    //描述信息  
    private String description;  
    //0 停售 1 起售  
    private Integer status;  
    //更新时间  
    private LocalDateTime updateTime;  
    //分类名称  
    private String categoryName;  
    //菜品关联的口味  
    private List<DishFlavor> flavors = new ArrayList<>();  
  
    //private Integer copies;  
}

三层架构代码:

/**  
 * 根据id查询菜品  
 * @param id  
 * @return  
 */  
@ApiOperation("根据id查询菜品")  
@GetMapping("/{id}")  
public Result<DishVO> getById(@PathVariable Long id){  
   log.info("根据id查询菜品:{}",id);  
     DishVO dishVO = dishService.getByIdWithFlavor(id);  
    return Result.success(dishVO);  
}
//根据id查询菜品  
DishVO getByIdWithFlavor(Long id);

/**  
 * 根据id查询菜品  
 * @param id  
 * @return  
 */  
public DishVO getByIdWithFlavor(Long id) {  
  
    //查询Dish  
    Dish dish = dishMapper.getById(id);  
    //查询DishFlavor  
    List<DishFlavor> flavors = dishFlavourMapper.getByDishId(id);  
  
    DishVO dishVO = new DishVO();  
    BeanUtils.copyProperties(dish,dishVO);  
    dishVO.setFlavors(flavors);  
  
    //封装数据  
    return dishVO;  
}
/**  
 * 根据菜品id查询口味数据  
 * @param id  
 * @return  
 */  
@Select("select * from dish_flavor where dish_id = #{id}")  
List<DishFlavor> getByDishId(Long id);

 接口二:修改菜单

三层架构:

/**  
 * 更新菜品  
 * @return  
 */  
@ApiOperation("更新菜品")  
@PutMapping  
public Result update(@RequestBody DishDTO dishDTO){  
    log.info("更新菜品:{}",dishDTO);  
    dishService.updateWithFlavor(dishDTO);  
    return Result.success();  
}
//更新菜品  
void updateWithFlavor(DishDTO dishDTO);
   /**  
     * 更新菜品  
     * @param dishDTO  
     */  
    public void updateWithFlavor(DishDTO dishDTO) {  
//        由于口味的状态太多,可能修改,可能不该,也可能删除,所以直接先删除再插入  
  
        //修改菜品表的基本信息  
        Dish dish = new Dish();  
        BeanUtils.copyProperties(dishDTO,dish);  
        dishMapper.update(dish);  
  
        //删除口味表的数据  
        dishFlavourMapper.deleteByDishIds(dish.getId());  
        //插入新的口味数据  
        List<DishFlavor> flavors = dishDTO.getFlavors();  
            if(flavors!=null && flavors.size()>0){  
            for (DishFlavor flavor : flavors) {  
                flavor.setDishId(dish.getId());  
            }  
            //批量插入  
            dishFlavourMapper.insertBatch(flavors);  
        }  
    }
/**  
 * 更新菜品数据  
 * @param dish  
 */  
@AutoFill(OperationType.UPDATE)  
void update(Dish dish);
<!--    更新菜品-->  
    <update id="update">  
        update sky_take_out.dish  
        <set>  
            <if test="name != null">  
                name = #{name},  
            </if>  
            <if test="categoryId != null">  
                category_id = #{categoryId},  
            </if>  
            <if test="price != null">  
                price = #{price},  
            </if>  
            <if test="image != null">  
                image = #{image},  
            </if>  
            <if test="description != null">  
                description = #{description},  
            </if>  
            <if test="updateTime != null">  
                update_time = #{updateTime},  
            </if>  
            <if test="updateUser != null">  
                update_user = #{updateUser},  
            </if>  
        </set>  
    <where> id = #{id}</where>  
    </update>


 二、Redis使用

五种Redis基本数据类型

Redis基本数据类型的操作·

字符串类型(String)

set key value --创建字符串

get key -- 获取字符串

incr key -- 返回自加1后的值(注意:只有key对应的value是数字的时候才能进行自加,否则会报错)

decr key-- 返回自减少1后的值(注意:只有key对应的value是数字的时候才能进行自加,否则会报错)

INCRBY KEY NUMBER --指定增加某个数

DECRBY KEY NUMBER --指定减少某个数

INCRFLOAT KEY NUMBER --增加float型的数

 2.哈希类型(Hash)

一.创建哈希

HSET KEY FILED VALUES --单个创建

HMSET KEY FILED1 VALUES1 FILED2 VALUES2... -- 多个创建

二.获取哈希某个属性的值

HGET KEY FILED --单个获取

HMGET KEY FILED1 FILED2 ...--多个获取

HGETALL KEY -获取目标key下所有的filed与对应的值

三.检测是否存在

HEXIST KEY FILED
--检测想要的key对象有没有某个方面比如CAR想要看有没有价格方面信息等等

HSETNX KEY FILED VALUE-- hsetnx(hset if not exist)
如果不存在某个方面的情况下,设置某个方面与其值,比如我设置CAR price 10 可以知道 CAR 已经存在对应的price,并且返回值是(integer)0意味着创建失败

四.哈希键的修改

1.HINCRBY FILED VALUES +/-NUMBER--
修改某个方面的值比如price ,并且通过值得正负实现是增还是减

2.HDEL key FILED/ FILED2 /FILED3 ...--删除某个方面

五.其它

HKEYS KEY --获取某个键对应的所有方面(域),比如CAR 能获取到其price name 等等

HVALS KEY --与hkeys不同的是,hvals key获取的是某个键对应所有方面的值

HLEN KEY  -- 计算并返回某个键名对应有多少个域filed

 3.列表类型(list)

一、修改
LPUSH  key --即是left push 从左插入,并返回当前列表内元素的个数

RPUSH  key --对应的是right push 从右边插入,并返回当前列表内元素的个数

LPOP  key --输出列表最左边的值,再将其删除

RPOP key --输出列表最右边的值,再将其删除

LREM key count value --从列表中删除指定数量的匹配元素。

        注意LREM key count value中

        如果count>0 则意味着从左到右开始删除count 个值为 value的元素

        如果count<0 则意味着从右到左开始删除count 个值为 value的元素
二.获取列表以及相关信息

LRANGE KEY 0 -1    --表示从第0个开始,-1(表示全部)输出(从左到右输出)

LRANGE KEY 0 2    --表示从第0个开始,到第2个输出

LINDEX KEY index --获取列表中指定索引位置的元素。

LLEN KEY --获取列表的长度(元素个数)

三、列表的修改
LINSERT key BEFORE|AFTER pivot value --将值插入到列表中某个元素之前或之后

 4.集合类型(set)

1.集合的创建删除与查询

SADD KEY MEMBER / MEMBER1 / MEMBER2...--创建集合

SREM KEY MEMBER / MEMBER1 / MEMBER2... --删除集合key中的成员

SMEMBERS KEY --查看集合内key所有的成员

SISMEMBER KEY MEMBER --集合中是否存在
SDIFF KEY1 KEY2 --集合相减,

举例有两个社团key1 和key2那么当需求社团成员只报了key1社团没有报社团key2时候就可以用集合相减

SINTER KEY1 KEY2--集合取交集

还是如上的例子,当我需要即报名了key1社团和key2社团的成员时候就可以用SINTER KEY1 KEY2 来计算

SUNION KEY1 KEY2--集合取并集

5.有序集合类型(Zset)

一.有序集合的创建与查询

ZADD   KEY SCORE MEMBER/  SCORE  MEMBER 2 ...--创建有序集合

ZSCORE MEMBER --查询某个成员的分数

ZRANGE KEY START END [withscores]--从低到高进行排名 当加上with scores后缀时候不止有对应的成员排名,还会展示成员的分数

ZREVRABFE KEY START END [withscores]--reverse zrange 即对zrange命令的反转就是从高到低进行排名

ZCARD KEY    --统计zset内成员的个数

ZCOUNT KEY MIN MAX --统计集合key成员中分数段为[min,max]的成员个数

ZRANK KEY MEMBER --查询某个成员在集合内排第几名
二、有序集合的修改
ZINCRBY KEY INCRESEMENT MEMBER-- 对集合key内成员的score进行操作可以通过最后INCRESEMENT 的+ - 进行增加或者减少

ZREM KEY MEMBER1 / MEMBER2...--删除集合key中的成员member1

 通过RAM对Redis数据库进行操作

先下载redis,之后在文件夹中找到两个核心程序

下载RAM

通过RAM进行配置

 通过Java代码对Redis数据库进行操作

1.导入Maven依赖

<dependency>  
    <groupId>org.springframework.boot</groupId>  
    <artifactId>spring-boot-starter-data-redis</artifactId>  
</dependency>

 2.配置数据源:

spring:  
  redis:  
    host: localhost  
    port: 6379  
    password: 123456
    database: 10

3.设置配置类

@Configuration  
@Slf4j  
public class RedisConfiguration {  
    @Bean  
    public RedisTemplate redisTemplate(RedisConnectionFactory redisCollectionFactory){  
        log.info("开始创造redisTemplate模板");  
        //创建模板对象
        RedisTemplate redisTemplate = new RedisTemplate(); 
         
        //设置连接工厂  
        redisTemplate.setConnectionFactory(redisCollectionFactory);  
        
        //设置key序列化器  
        redisTemplate.setKeySerializer(new StringRedisSerializer());  
        return redisTemplate;  
    }  
}

通过Java使用Redis实现对五种数据类型的操作案例:
1.创建测试类(需要与项目com.sky同级)

2.创建对应的操作类

@Test  
public void test(){  
    //操作字符串  
    ValueOperations valueOperations = redisTemplate.opsForValue();  
    //操作hash  
    HashOperations hashOperations = redisTemplate.opsForHash();  
    //操作list  
    ListOperations listOperations = redisTemplate.opsForList();  
    //操作set  
    SetOperations setOperations = redisTemplate.opsForSet();  
    //操作zset  
    ZSetOperations zSetOperations = redisTemplate.opsForZSet();  
}

 通过Java对Redis的常用类型的操作

一、操作字符串类型

/**  
 * 测试字符串  
 */  
@Test  
public void ValueTest(){  
    //redis操作字符串常用方法有:set get setIfAbsent setIfPresent setIfAbsent setIfPresent getAndSet  
   //1.操作字符串  
    ValueOperations valueOperations = redisTemplate.opsForValue();  
  
    //设置key-value  
    valueOperations.set("name","AlphaMilk");  
    //获取key的value  
    String name = (String) valueOperations.get("name");  
    System.out.println(name);  
  
    //设置key-value并设置过期时间  
    valueOperations.set("age",14,13, TimeUnit.MINUTES);  
    //获取key的value和过期时间  
    valueOperations.get("age");  
  
    //设置并判断key-value是否存在  
    valueOperations.setIfAbsent("code","1");  
    valueOperations.setIfAbsent("code","2");  
  
}

二.操作hash类型

/**  
 * 测试hash  
 */@Test  
public void  HashTest(){  
    //常用方法有:put get delete hasKey keys values entries  
    HashOperations hashOperations = redisTemplate.opsForHash();  
    hashOperations.put("user","name","AlphaMilk");  
    hashOperations.put("user","age","14");  
  
    //获取hash的key的value  
    String name = (String) hashOperations.get("user","name");  
    System.out.println(name);  
  
    //获取hash的所有key  
    Set user = hashOperations.keys("user");  
    System.out.println(user);  
  
    //获取hash的所有value  
    List list = hashOperations.values("user");  
    System.out.println(list);  
  
    //删除hash的key  
    hashOperations.delete("user","name");  
  
}

三.操作list类型

@Test  
public void ListTest(){  
    //常用方法有:leftPush leftPushAll rightPush rightPushAll leftPop rightPop index range trim  
    ListOperations listOperations = redisTemplate.opsForList();  
  
    //左插入  
    listOperations.leftPush("list","1");  
    //右插入  
    listOperations.rightPush("list","2");  
  
    //多个左插入  
    listOperations.leftPushAll("list","3","4","5");  
    //多个右插入  
    listOperations.rightPushAll("list","6","7","8");  
  
    //左弹出  
    String list1 = (String) listOperations.leftPop("list");  
    System.out.println(list1);  
    //右弹出  
    String list2 = (String) listOperations.rightPop("list");  
    System.out.println(list2);  
  
    //获取指定位置的元素  
    String value = (String) listOperations.index("list",1);  
    System.out.println(value);  
  
    //获取指定范围的元素  
    List list = listOperations.range("list",0,2);  
    System.out.println(list);  
  
    //修剪  
    listOperations.trim("list",1,2);  
}

 四、操作set类型

@Test  
public void SetTest(){  
    //常用方法有:add remove members size isMember intersect union difference  
    SetOperations setOperations = redisTemplate.opsForSet();  
  
    //添加元素  
    setOperations.add("set1","1","2","3","4","5");  
    //获取元素  
    Set set1 = setOperations.members("set1");  
    System.out.println(set1);  
    //获取元素个数  
    Long size = setOperations.size("set1");  
    System.out.println(size);  
    //删除元素  
    setOperations.remove("set1","1");  
    //判断元素是否存在  
    Boolean isMember = setOperations.isMember("set1","1");  
    System.out.println(isMember);  
    //创建集合set2  
    setOperations.add("set2","3","4","5","6","7");  
    //求交集  
    Set intersect = setOperations.intersect("set","set2");  
    System.out.println(intersect);  
    //求并集  
    Set union = setOperations.union("set1","set2");  
    System.out.println(union);  
    //求差集  
    Set difference = setOperations.difference("set1","set2");  
    System.out.println(difference);  
}

五、操作ZSet类型

@Test  
public void ZSetTest(){  
    //常用方法有:add remove range rangeByScore size rank reverseRank incrementScore  
    ZSetOperations zSetOperations = redisTemplate.opsForZSet();  
  
    //添加元素  
    zSetOperations.add("zset","1",1);  
  
    //获取元素  
    Set zset = zSetOperations.range("zset",0,1);  
    System.out.println(zset);  
  
    //获取元素个数  
    Long size = zSetOperations.size("zset");  
    System.out.println(size);  
  
    //删除元素  
    zSetOperations.remove("zset","1");  
  
    //添加多个元素  
    zSetOperations.add("zset","2",2);  
    zSetOperations.add("zset","3",3);  
    zSetOperations.add("zset","4",4);  
  
    //获取指定范围的元素  
    Set zset1 = zSetOperations.range("zset",0,2);  
    System.out.println(zset1);  
  
    //获取排名  
    Long rank = zSetOperations.rank("zset","2");  
    System.out.println(rank);  
  
    //获取倒序排名  
    Long reverseRank = zSetOperations.reverseRank("zset","2");  
    System.out.println(reverseRank);  
  
    //增加分数  
    Double incrementScore = zSetOperations.incrementScore("zset","2",2);  
    System.out.println(incrementScore);  
  
    //获取指定分数范围的元素  
    Set zset2 = zSetOperations.rangeByScore("zset",2,4);  
    System.out.println(zset2);  
}

六、通用命令

@Test  
public void CommonTest(){  
    //通用命令常用方法有:delete expire expireAt hasKey keys  
    //删除key  
    redisTemplate.delete("name");  
    //设置过期时间  
    redisTemplate.expire("age",10,TimeUnit.SECONDS);  
    //设置过期时间  
    redisTemplate.expireAt("age", Instant.ofEpochSecond(10));  
    //判断key是否存在  
    Boolean hasKey = redisTemplate.hasKey("age");  
    System.out.println(hasKey);  
    //获取所有key  
    Set keys = redisTemplate.keys("*");  
    System.out.println(keys);  
}

实战:店铺状态设置


为什么要通过Redis设置?因为存储店铺状态如果用到mysql,那么需要一张单独的表去存放,过于浪费并且效率不高。

代码实现:
1.实现管理端的设置状态与获取状态

//关键一步:因为同时存在用户端和管理端,需要通过Bean
名称区别开来,否则会报错,出现同个shopController冲突
@RestController("adminShopController") 
@Slf4j  
@RequestMapping("/admin/shop")  
@Api(tags = "店铺设置")  
public class ShopController {  
    private static  final  String SHOP_STATUS = "SHOP_STATUS";  
  
    //引入redisTemplate  
    @Autowired  
    private RedisTemplate redisTemplate;  
  
    /**  
     * 管理端的设置店铺状态  
     * @return  
     */  
    @PutMapping("/{status}")  
    @ApiOperation("修改店铺状态")  
    public Result setStatus(@PathVariable Integer status){  
        log.info("设置店铺状态为{}",status==1?"营业中":"打样中");  
        ValueOperations valueOperations = redisTemplate.opsForValue();  
        valueOperations.set(SHOP_STATUS,status);  
        return Result.success();  
    }  
    /**  
     * 获取店铺状态  
     * @return  
     */  
    @GetMapping("/status")  
    @ApiOperation("获取店铺状态")  
    public Result getStatus(){  
        Integer status = (Integer) redisTemplate.opsForValue().get(SHOP_STATUS);  
        log.info("当前店铺状态为{}",status==1?"营业中":"打样中");  
        return Result.success(status);  
    }  
}

 2.设置用户端的查询店铺状态

@RestController("userShopController")  
@Slf4j  
@RequestMapping("/user/shop")  
@Api(tags = "用户端店铺使用")  
public class ShopController {  
    private static  final  String SHOP_STATUS = "SHOP_STATUS";  
  
    //引入redisTemplate  
    @Autowired  
    private RedisTemplate redisTemplate;  
      
    /**  
     * 获取店铺状态  
     * @return  
     */  
    @GetMapping("/status")  
    @ApiOperation("获取店铺状态")  
    public Result getStatus(){  
        Integer status = (Integer) redisTemplate.opsForValue().get(SHOP_STATUS);  
        log.info("当前店铺状态为{}",status==1?"营业中":"打样中");  
        return Result.success(status);  
    }  
}

2.设置用户端的查询店铺状态

@RestController("userShopController")  
@Slf4j  
@RequestMapping("/user/shop")  
@Api(tags = "用户端店铺使用")  
public class ShopController {  
    private static  final  String SHOP_STATUS = "SHOP_STATUS";  
  
    //引入redisTemplate  
    @Autowired  
    private RedisTemplate redisTemplate;  
      
    /**  
     * 获取店铺状态  
     * @return  
     */  
    @GetMapping("/status")  
    @ApiOperation("获取店铺状态")  
    public Result getStatus(){  
        Integer status = (Integer) redisTemplate.opsForValue().get(SHOP_STATUS);  
        log.info("当前店铺状态为{}",status==1?"营业中":"打样中");  
        return Result.success(status);  
    }  
}

 

 为了解决混用问题,需要进行创建多个Docket


三、使用HttpClient进行调用其他服务器接口

当一个项目足够大的时候,一台服务器的性能可能无法支撑这个项目的正常运转。这时候就需要进行多个服务器来共同承载一个项目。而服务器之间的通信就需要依赖像HttpClient,Okhttp这类的客户端编程工具包

 使用案例:
导入maven坐标

<dependency>  
    <groupId>org.apache.httpcomponents</groupId>  
    <artifactId>httpclient</artifactId>  
    <version>4.5.13</version>  
</dependency>

 发送Get请求

/*  
 *通过测试类测试HttpClient发送get请求  
 */@Test  
public void testGet() throws IOException {  
    //1.创建HttpClient对象  
    CloseableHttpClient client = HttpClients.createDefault();  
  
    //2.创建HttpGet对象  
    HttpGet httpGet = new HttpGet("http://localhost:8080/user/shop/status");  
  
    //3.发送请求  
    CloseableHttpResponse response = client.execute(httpGet);  
  
    //4.获取状态码 与数据  
    int statusCode = response.getStatusLine().getStatusCode();  
    System.out.println("状态码为"+statusCode);  
  
    HttpEntity entity = response.getEntity();  
    String string = EntityUtils.toString(entity);  
    System.out.println("数据为"+string);  
    //5.关闭资源  
    response.close();  
    client.close();  
  
}

 发送POST请求

/*  
 *通过测试类测试HttpClient发送post请求  
 */@Test  
public void POSTTest() throws IOException {  
    //1.创建HttpClient对象  
    CloseableHttpClient client = HttpClients.createDefault();  
    //2.创建HttpPost对象  
    HttpPost httpPost = new HttpPost("http://localhost:8080/admin/employee/login");  
  
    //通过fastjson对Json数据格式封装  
    JSONObject jsonObject = new JSONObject();  
    jsonObject.put("username","admin");  
    jsonObject.put("password","123456");  
  
    StringEntity entity = new StringEntity(jsonObject.toString());  
    //指定请求编码方式  
    entity.setContentEncoding("UTF-8");  
    //数据格式  
    entity.setContentType("application/json");  
    httpPost.setEntity(entity);  
  
    //3.发送请求  
    CloseableHttpResponse response = client.execute(httpPost);  
  
    //4.获取状态码 与数据  
    int statusCode = response.getStatusLine().getStatusCode();  
    System.out.println("状态码为"+statusCode);  
  
    HttpEntity entity1 = response.getEntity();  
    String string = EntityUtils.toString(entity1);  
    System.out.println("数据为"+string);  
  
    //5.关闭资源  
    response.close();  
    client.close();  
}

 这里可以看到,使用HttpClient有点复杂,所以可以借助以下工具类进行简化操作

/**  
 * Http工具类  
 */  
public class HttpClientUtil {  
  
    static final  int TIMEOUT_MSEC = 5 * 1000;  
  
    /**  
     * 发送GET方式请求  
     * @param url  
     * @param paramMap  
     * @return  
     */  
    public static String doGet(String url,Map<String,String> paramMap){  
        // 创建Httpclient对象  
        CloseableHttpClient httpClient = HttpClients.createDefault();  
  
        String result = "";  
        CloseableHttpResponse response = null;  
  
        try{  
            URIBuilder builder = new URIBuilder(url);  
            if(paramMap != null){  
                for (String key : paramMap.keySet()) {  
                    builder.addParameter(key,paramMap.get(key));  
                }  
            }  
            URI uri = builder.build();  
  
            //创建GET请求  
            HttpGet httpGet = new HttpGet(uri);  
  
            //发送请求  
            response = httpClient.execute(httpGet);  
  
            //判断响应状态  
            if(response.getStatusLine().getStatusCode() == 200){  
                result = EntityUtils.toString(response.getEntity(),"UTF-8");  
            }  
        }catch (Exception e){  
            e.printStackTrace();  
        }finally {  
            try {  
                response.close();  
                httpClient.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
  
        return result;  
    }  
  
    /**  
     * 发送POST方式请求  
     * @param url  
     * @param paramMap  
     * @return  
     * @throws IOException  
     */    public static String doPost(String url, Map<String, String> paramMap) throws IOException {  
        // 创建Httpclient对象  
        CloseableHttpClient httpClient = HttpClients.createDefault();  
        CloseableHttpResponse response = null;  
        String resultString = "";  
  
        try {  
            // 创建Http Post请求  
            HttpPost httpPost = new HttpPost(url);  
  
            // 创建参数列表  
            if (paramMap != null) {  
                List<NameValuePair> paramList = new ArrayList();  
                for (Map.Entry<String, String> param : paramMap.entrySet()) {  
                    paramList.add(new BasicNameValuePair(param.getKey(), param.getValue()));  
                }  
                // 模拟表单  
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);  
                httpPost.setEntity(entity);  
            }  
  
            httpPost.setConfig(builderRequestConfig());  
  
            // 执行http请求  
            response = httpClient.execute(httpPost);  
  
            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");  
        } catch (Exception e) {  
            throw e;  
        } finally {  
            try {  
                response.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
  
        return resultString;  
    }  
  
    /**  
     * 发送POST方式请求  
     * @param url  
     * @param paramMap  
     * @return  
     * @throws IOException  
     */    public static String doPost4Json(String url, Map<String, String> paramMap) throws IOException {  
        // 创建Httpclient对象  
        CloseableHttpClient httpClient = HttpClients.createDefault();  
        CloseableHttpResponse response = null;  
        String resultString = "";  
  
        try {  
            // 创建Http Post请求  
            HttpPost httpPost = new HttpPost(url);  
  
            if (paramMap != null) {  
                //构造json格式数据  
                JSONObject jsonObject = new JSONObject();  
                for (Map.Entry<String, String> param : paramMap.entrySet()) {  
                    jsonObject.put(param.getKey(),param.getValue());  
                }  
                StringEntity entity = new StringEntity(jsonObject.toString(),"utf-8");  
                //设置请求编码  
                entity.setContentEncoding("utf-8");  
                //设置数据类型  
                entity.setContentType("application/json");  
                httpPost.setEntity(entity);  
            }  
  
            httpPost.setConfig(builderRequestConfig());  
  
            // 执行http请求  
            response = httpClient.execute(httpPost);  
  
            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");  
        } catch (Exception e) {  
            throw e;  
        } finally {  
            try {  
                response.close();  
            } catch (IOException e) {  
                e.printStackTrace();  
            }  
        }  
  
        return resultString;  
    }  
    private static RequestConfig builderRequestConfig() {  
        return RequestConfig.custom()  
                .setConnectTimeout(TIMEOUT_MSEC)  
                .setConnectionRequestTimeout(TIMEOUT_MSEC)  
                .setSocketTimeout(TIMEOUT_MSEC).build();  
    }  
  
}

四、微信小程序开发

注册

注册后下载微信开发者工具

微信开发者工具介绍

微信开发者工具入门案例开发

动态信息展示:

<!--index.wxml-->
<view class="container">
  <view>
    {{msg}}
  </view>
</view>
// index.js
// const app = getApp()
Page({
  data:{
    msg: 'xxxxx'
  }

});

wxml:模拟按钮获取用户信息

  <view>

  <button type="primary" bindtap="getUserInfo">获取用户信息</button>

  <view>

     昵称: {{nickName}}

  </view>

  <!-- 图像 -->

  <image src="{{url}}"></image>

  </view>

 js:

  //获取用户信息

    getUserInfo(){

    wx.getUserProfile({

      desc: '获取用户信息',

      sucess:(res)=>{

          console.log(res.userInfo)

          //为数据赋值

          nickName: res.userInfo.nickName

          url: res.userInfo.avataUrl

      }

    })}

 获取用户code

wxml

<!-- 微信登陆 -->

  <view>

      <button type="warn" bindtap="wxLogin">微信登陆</button>

      授权码:{{code}}

  </view>

JS

Page({
  data:{
    msg: 'xxxx',
    nickName: '',
    url: '',
    code: ''
  },
//获取授权码
    wxLogin(){
        wx.login({
          success : (res)=>{
            console.log(res.code)
          }
        })

    }

展示商品:通过异步请求获取商品信息

wxml:

  <view>
      <button type="default" bindtap="sendRequest">发送请求</button>
  </view>

 JS:

    //发送请求
    sendRequest(){
        wx.request({
          url: 'http://localhost:8080/user/shop/status',
          method:'Get',
          success: (res)=>{
            console.log(res.data)
          }
        })
    }

 实现微信登陆:
1.导入小程序代码

 
2.实现微信登陆
1.登陆流程

 

## 调用auth.code2Session方式
HTTPS 调用

GET https://api.weixin.qq.com/sns/jscode2session 

 

 配置wechat所需要的配置项
application.yml中jwt配置

sky:  
  jwt:  
    # 设置jwt签名加密时使用的秘钥  
    admin-secret-key: itcast  
    # 设置jwt过期时间  
    admin-ttl: 7200000  
    # 设置前端传递过来的令牌名称  
    admin-token-name: token  
    #  设置用户的jwt签名加密时使用的秘钥  
    user-secret-key: alphaMilk  
    # 设置用户的jwt过期时间  
    user-ttl: 7200000  
    # 设置用户的jwt签名加密时使用的秘钥  
    user-token-name: authentication

 yml

#配置Wechat  
  wechat:  
    appid: XXXXX 
    secret: XXXXXX

用户端登陆请求对应的DTO:

/**  
 * C端用户登录  
 */  
@Data  
public class UserLoginDTO implements Serializable {  
    private String code;  
}

用户端返回对应的VO

@Data  
@Builder  
@NoArgsConstructor  
@AllArgsConstructor  
public class UserLoginVO implements Serializable {  
  
    private Long id;  
    private String openid;  
    private String token;  
  
}

Controller:

/**  
 * 用户登录  
 *  
 * @param userLoginDTO 用户登录信息  
 * @return 用户登录信息  
 */  
@ApiOperation(value = "用户登录")  
@PostMapping("/login")  
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {  
    log.info("用户登录,参数:{}", userLoginDTO);  
    // 微信用户登录  
    User user = userService.wxlogin(userLoginDTO);  
      
    // 返回用户JWT  
    Map<String, Object> claims = new HashMap<>();  
    claims.put(JwtClaimsConstant.USER_ID, user.getId());  
    String jwt = JwtUtil.createJWT(jwtProperties.getUserSecretKey(), jwtProperties.getUserTtl(), claims);  
      
    //封装VO对象  
    UserLoginVO userLoginVO = UserLoginVO.builder()  
            .id(user.getId())  
            .openid(user.getOpenid())  
            .token(jwt)  
            .build();  
    return Result.success(userLoginVO);  
}

Service:

public interface UserService {  
  
    /**  
     * 用户登录  
     *  
     * @param userLoginDTO 用户登录信息  
     * @return 用户信息  
     */  
    User wxlogin(UserLoginDTO userLoginDTO);  
}

ServiceImpl:

@Service  
public class UserServiceImpl implements UserService {  
  
    @Autowired  
    UserMapper userMapper;  
  
    //微信接口url  
    public static final String WX_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";  
  
    @Autowired  
    WeChatProperties weChatProperties;  
  
    /**  
     * WX用户登录  
     *  
     * @param userLoginDTO 用户登录信息  
     * @return 用户信息  
     */  
    public User wxlogin(UserLoginDTO userLoginDTO) {  
        //1.调用wx接口服务获取openid  
       String openid = getOpenId(userLoginDTO.getCode());  
  
        //2.判断是否获取到openid 如果是空抛出异常  
        if (openid == null) {  
            throw new LoginFailedException(MessageConstant.LOGIN_FAILED);  
        }  
  
        //3.判断是否是新用户,如果是新用户,保存用户信息  
        User user = userMapper.getUserByOpenid(openid);  
        if (user == null){  
            user = User.builder()  
                    .openid(openid)  
                    .createTime(LocalDateTime.now())  
                    .build();  
            userMapper.insert(user);  
        }  
  
        //4.返回用户信息  
        return user;  
    }  
    private String getOpenId(String code){  
        //1.调用wx接口服务获取openid  
        Map<String, String> map = new HashMap<>();  
  
        map.put("appid", weChatProperties.getAppid());  
        map.put("secret", weChatProperties.getSecret());  
        map.put("js_code", code);  
        map.put("grant_type", "authorization_code");  
  
        String string = HttpClientUtil.doGet(WX_LOGIN_URL, map);  
  
        JSONObject jsonObject = JSON.parseObject(string);  
        String openid = (String) jsonObject.get("openid");  
        return openid;  
    }  
}

mapper:

@Mapper  
public interface UserMapper {  
  
    /**  
     * 插入用户  
     *  
     * @param user 用户  
     */  
     void insert(User user);  
  
    /**  
     * 根据openid查询用户  
     *  
     * @param openid openid  
     * @return 用户  
     */  
    @Select("select * from user where openid = #{openid}")  
    User getUserByOpenid(String openid);  
}

xml:

<?xml version="1.0" encoding="UTF-8" ?>  
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"  
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >  
<mapper namespace="com.sky.mapper.UserMapper">  
    <insert id="insert" useGeneratedKeys="true" keyProperty="id">  
        insert into sky_take_out.user(openid, name, phone, sex, id_number, avatar, create_time)  
        VALUES (#{openid},#{name},#{phone},#{sex},#{idNumber},#{avatar},#{createTime})    </insert>  
</mapper>

小程序用户端拦截器
通过资源类快速导入jwt相关信息:

@Component  
@ConfigurationProperties(prefix = "sky.jwt")  
@Data  
public class JwtProperties {  
  
    /**  
     * 管理端员工生成jwt令牌相关配置  
     */  
    private String adminSecretKey;  
    private long adminTtl;  
    private String adminTokenName;  
  
    /**  
     * 用户端微信用户生成jwt令牌相关配置  
     */  
    private String userSecretKey;  
    private long userTtl;  
    private String userTokenName;  
  
}
/**  
 * jwt令牌校验的拦截器  
 */  
@Component  
@Slf4j  
public class JwtTokenUserInterceptor implements HandlerInterceptor {  
  
    @Autowired  
    private JwtProperties jwtProperties;  
  
    /**  
     * 校验jwt  
     *     * @param request  
     * @param response  
     * @param handler  
     * @return  
     * @throws Exception  
     */    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {  
        //判断当前拦截到的是Controller的方法还是其他资源  
        if (!(handler instanceof HandlerMethod)) {  
            //当前拦截到的不是动态方法,直接放行  
            return true;  
        }  
        //1、从请求头中获取令牌  
        String token = request.getHeader(jwtProperties.getUserTokenName());  
        //2、校验令牌  
        try {  
            log.info("jwt校验:{}", token);  
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);  
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());  
            log.info("当前用户id:", userId);  
            //通过ThreadLocal保存员工id  
            BaseContext.setCurrentId(userId);  
            //3、通过,放行  
            return true;  
        } catch (Exception ex) {  
            //4、不通过,响应401状态码  
            response.setStatus(401);  
            return false;  
        }  
    }  
}

配置开启拦截器

@Configuration  
@Slf4j  
public class WebMvcConfiguration extends WebMvcConfigurationSupport {  
  
    @Autowired  
    private JwtTokenAdminInterceptor jwtTokenAdminInterceptor;  
  
    // 注入用户拦截器  
    @Autowired  
    private JwtTokenUserInterceptor jwtTokenUserInterceptor;  
  
    /**  
     * 注册自定义拦截器  
     *  
     * @param registry  
     */  
    protected void addInterceptors(InterceptorRegistry registry) {  
        log.info("开始注册自定义拦截器...");  
//          管理员拦截器  
        registry.addInterceptor(jwtTokenAdminInterceptor)  
                .addPathPatterns("/admin/**")  
                .excludePathPatterns("/admin/employee/login");  
//        用户拦截器  
        registry.addInterceptor(jwtTokenUserInterceptor)  
                .addPathPatterns("/user/**")  
                .excludePathPatterns("/user/user/login")  
                .excludePathPatterns("/user/shop/status");  
    }
}

导入商品浏览功能
需求分析:

 三层架构

/**  
 * 根据分类id查询菜品  
 *  
 * @param categoryId  
 * @return  
 */  
@GetMapping("/list")  
@ApiOperation("根据分类id查询菜品")  
public Result<List<DishVO>> list(Long categoryId) {  
      
    Dish dish = new Dish();  
    dish.setCategoryId(categoryId);  
    dish.setStatus(StatusConstant.ENABLE);//查询起售中的菜品  
  
    List<DishVO> list = dishService.listWithFlavor(dish);  
  
    return Result.success(list);  
}
//TODO:测试根据分类id查询菜品  
List<Dish> queryByCategoryId(Long id);
/**  
 * 条件查询菜品和口味  
 * @param dish  
 * @return  
 */  
List<DishVO> listWithFlavor(Dish dish);
/**  
 * 根据分类id查询菜品  
 * @param categoryId  
 * @return  
 */  
public List<Dish> list(Long categoryId) {  
    Dish dish = Dish.builder()  
            .categoryId(categoryId)  
            .status(StatusConstant.ENABLE)  
            .build();  
    return dishMapper.list(dish);  
}
/**  
 * 条件查询菜品和口味  
 * @param dish  
 * @return  
 */  
public List<DishVO> listWithFlavor(Dish dish) {  
    List<Dish> dishList = dishMapper.list(dish);  
  
    List<DishVO> dishVOList = new ArrayList<>();  
  
    for (Dish d : dishList) {  
        DishVO dishVO = new DishVO();  
        BeanUtils.copyProperties(d,dishVO);  
  
        //根据菜品id查询对应的口味  
        List<DishFlavor> flavors = dishFlavourMapper.getByDishId(d.getId());  
  
        dishVO.setFlavors(flavors);  
        dishVOList.add(dishVO);  
    }  
  
    return dishVOList;  
}

 

 

相关文章:

  • c# 新建不重名的唯一文件夹
  • STM32 HAL库时钟系统详解
  • AndroidTV 当贝播放器-v1.5.2-官方简洁无广告版
  • SAP-ABAP:BAPI_ACC_DOCUMENT_POST 详解(总账、应收账款、应付账款等业务场景的自动化集成)
  • Android 存储路径
  • 大模型学习八:‌Sealos 私有化部署之VMware 安装ubuntu22.04 虚拟机安装(实操)
  • 【产品】ToB产品需求分析
  • 【Java SE】泛型详解
  • GAT-GRAPH ATTENTION NETWORKS(论文笔记)
  • 计算机组成原理笔记(十四)——3.4指令类型
  • 某益网络面经总结
  • 单链表专题(C语言)
  • 基于SpringBoot的电影订票系统(源码+数据库+万字文档+ppt)
  • 架构师面试(三十):IM 分层架构
  • 架构生命周期(高软57)
  • CSS padding(填充)学习笔记
  • C# Winform 入门(16)之图片合成
  • Linux--线程概念与控制
  • 突破边界:从 C# 到 Python 的范式跃迁与实战指南
  • 图像分割基础学习
  • 来论|受美国“保护”,日本民众要付出什么代价?
  • 央行4月开展12000亿元买断式逆回购操作
  • 学有质量、查有力度、改有成效,广大党员干部落实中央八项规定精神
  • 特朗普加征关税冲击波:美国零售、汽车、航空、科技企业纷纷预警业绩波动
  • 神舟十九号载人飞行任务取得圆满成功
  • 结婚这件事,年轻人到底怎么想的?