苍穹外卖Day(6)(7)
然后wx.request可以法器业务请求,开发者服务器可以解析token,最终返回数据。Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如: EHCache Caffeine Redis。3个controller,2个service,2个serviceImpl,1个mapper,1个mapper.xml。Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要
1.首先根据课件创建注册好自己的小程序。
1.1index.wxml(pages/index完整代码)
<view class="container">
<view>
{{msg}}
</view>
<view>
<button bindtap="getUserInfo" type="warn">获取用户信息</button>
昵称: {{nickName}}
<image style="width: 100px;height: 100px;" src="{{url}}"></image>
</view>
<view>
<button bindtap="wxLogin" type="warn">微信登录</button>
授权码:{{code}}
</view>
<view>
<button bindtap="sendRequest" type="default">发送请求</button>
</view>
</view>
1.2index.js(pages/index完整代码)
Page({
data:{
msg:'hello world',
nickName: '',
url:'',
code:''
},
//获取微信用户的头像和昵称
getUserInfo(){
wx.getUserProfile({
desc: '获取用户信息',
success: (res)=>{
console.log(res.userInfo);
//为数据赋值
this.setData({
nickName: res.userInfo.nickName,
url: res.userInfo.avatarUrl
})
}
})
},
//微信登录,获取微信用户的授权码
wxLogin(){
wx.login({
success : (res)=>{
console.log(res.code)
this.setData({
code:res.code
})
}
})
},
//发送请求
sendRequest(){
wx.request({
url: 'http://localhost:8080/user/shop/status',
method:'GET',
success:(res)=>{
console.log(res.data) //data代表整个响应回来的数据
}
})
}
})
1.3(微信小程序)导入
点击右上角的微信开发者工具:
![]()
点击上传按钮:

然后可以在版本管理界面看到,开发版本多了一项:

小程序代码是在day06文件夹中,需要事先解压一下:

然后在小程序开发助手点击导入:

这里要确保AppID是自己的:

下面是微信登录的官方文档:
点击上面的链接可以进入到如下界面:

下面是请求的参数:
使用PostMan进行测试,成功:

也可以直接在浏览器地址栏中构建:
微信登录流程:
小程序要调用wx.login获取code授权码,然后要调研wx.request()发送code授权码;
开发者服务器要向微信接口服务提交appid+appsecret+code,然后就可以获得session_key(会话密钥)和openid;
然后开发者服务器可以自定义登录状态,产生一个token令牌,然后返回自定义登录状态;
小程序可以把token令牌进行存储。然后wx.request可以法器业务请求,开发者服务器可以解析token,最终返回数据。
1.4编写配置代码
application-dev.yml
sky:
wechat:
appid: wx3910b10fd7db38d1
secret: f274884c2a56466016ebbcf009404e63
application.yml
sky:
wechat:
appid: ${sky.wechat.appit}
secret: ${sky.wechat.secret}
sky: jwt
user-secret-key: itheima
user-ttl: 7200000
user-token-name: authentication
1.5UserController类(/controller/user)
@RestController
@RequestMapping("/user/user")
@Api(tags="C端用户相关接口")
@Slf4j
public class UserController {
@Autowired
private UserService userService;
@Autowired
private JwtProperties jwtProperties;
//微信登录
@PostMapping("/login")
@ApiOperation("微信登录")
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){
log.info("微信用户登录;{}",userLoginDTO.getCode());
//微信登录
User user = userService.wxLogin(userLoginDTO);
//为微信用户生成jwt令牌
Map<String,Object> claims = new HashMap<>();
claims.put(JwtClaimsConstant.USER_ID,user.getId());
String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(),jwtProperties.getUserTtl(),claims);
UserLoginVO userLoginVO = UserLoginVO.builder()
.id(user.getId())
.openid(user.getOpenid())
.token(token)
.build();
return Result.success(userLoginVO);
}
}
1.6UserService类
package com.sky.service;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
public interface UserService {
//微信登录
User wxLogin(UserLoginDTO userLoginDTO);
}
1.7UserServiceImpl类
package com.sky.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sky.constant.MessageConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.entity.User;
import com.sky.exception.LoginFailedException;
import com.sky.properties.WeChatProperties;
import com.sky.service.UserService;
import com.sky.utils.HttpClientUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
public class UserServiceImpl implements UserService {
@Service
@Slf4j
public class UserServiceImpl implements UserService {
//微信服务接口地址
public static final String WX_LOGIN="http://api.weixin.qq.com/sns/jscode2session";
@Autowired
private WeChatProperties weChatProperties; //配置文件中传入的值会被放入配置类,所以只需要自动注入然后获取即可
@Autowired
private UserMapper userMapper;
//微信登录
public User wxLogin(UserLoginDTO userLoginDTO){
String openid = getOpenid(userLoginDTO.getCode());
//判断openid是否为空,如果为空登录失败,抛出业务异常
if(openid==null){
throw new LoginFailedException(MessageConstant.LOGIN_FAILED);
}
//判断当前用户是否为新用户(拿openid到用户表里查)
User user = userMapper.getByOpenid(openid);
//如果是新用户,自动完成注册
if(user == null){
user = User.builder()
.openid(openid)
.createTime(LocalDateTime.now())
.build();
userMapper.insert(user);
}
//返回这个用户对象
return user;
}
private String getOpenid(String code){
//调用微信接口服务,来获得当前微信用户的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 json = HttpClientUtil.doGet(WX_LOGIN,map);
JSONObject jsonObject = JSON.parseObject(json);
String openid = jsonObject.getString("openid");
return openid;
}
}
}
1.8UserMapper类(自己创建)
package com.sky.mapper;
import com.sky.entity.User;
public interface UserMapper {
/**
* 插入
* @param user
*/
void insert(User user);
/**
* 根据openid查询用户
* @param openid
* @return
*/
User getByOpenid(String openid);
}
1.9UserMapper.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">
<!--插入-->
<!--
useGeneratedKeys设置为true:在执行插入记录之后可以获取到数据库自动生成的主键值
keyProperty:指定Java对象的属性名
-->
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into user(openid,name,phone,sex,id_number,avatar,create_time)
values (#{openid},#{name},#{phone},#{sex},#{idNumber},#{avatar},#{createTime})
</insert>
</mapper>
1.10JwtTokenUserIntercepetor类(interceptor下创建)
@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {
@Autowired
private JwtProperties jwtProperties;
//校验jwt
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());
BaseContext.setCurrentId(userId);
log.info("当前员工id:", userId);
//3、通过,放行
return true;
} catch (Exception ex) {
//4、不通过,响应401状态码
response.setStatus(401);
return false;
}
}
}
然后要让这个拦截器生效:
在sky-server下的config包中的WebMvcConfiguration中写入如下代码:
@Autowired
private JwtTokenUserInterceptor jwtTokenUserInterceptor;
在addInterceptors中写入如下代码(注意下面addInterceptor里面是jwtTokenUserInterceptor):
registry.addInterceptor(jwtTokenUserInterceptor)
.addPathPatterns("/user/**")
.excludePathPatterns("/user/user/login")
.excludePathPatterns("/user/shop/status");
1.11然后在资料包中day06/代码导入/商品浏览中有9个文件:

3个controller,2个service,2个serviceImpl,1个mapper,1个mapper.xml。
注意下面2点:
1.上面的controller文件都要放在controller的user这个包下面。
2.有些已有的service或者mapper仅仅只需要拷贝方法,有些缺少的需要新建。
2.缓存菜品
2.1DishController类(/user)
// 构造Redis中的Key,规则为: dish_分类id
// 通过这个Key去Redis中查找缓存的数据
String key = "dish_" + categoryId;
// 首先查询Redis中是否存在缓存的菜品数据
List<DishVO> list = (List<DishVO>) redisTemplate.opsForValue().get(key);
// 如果Redis中有缓存数据,直接返回
if(list != null && list.size() > 0){
// 返回结果封装成功,直接从缓存中返回菜品列表
return Result.success(list);
}
// 如果Redis中没有缓存数据,则需要从数据库查询
Dish dish = new Dish();
dish.setCategoryId(categoryId); // 设置菜品的分类ID
dish.setStatus(StatusConstant.ENABLE); // 设置菜品的状态为“启用”状态,即查询起售中的菜品
// 查询数据库获取菜品列表,并包括菜品的口味信息
List<DishVO> dishList = dishService.listWithFlavor(dish);
// 将查询到的数据存入Redis缓存,以便下次查询时可以直接从缓存中获取
redisTemplate.opsForValue().set(key, dishList);
// 返回查询到的菜品列表
return Result.success(dishList);
2.2DishController类(/admin)
添加

//清理缓存数据
private void cleanCache(String pattern){
Set keys = redisTemplate.keys(pattern);
redisTemplate.delete(keys);
}
/**
* 新增菜品
* @param dishDTO
* @return
*/
@PostMapping
@ApiOperation("新增菜品")
public Result<String> save(@RequestBody DishDTO dishDTO) {
log.info("新增菜品:{}",dishDTO);
dishService.saveWithFlavor(dishDTO);
//添加这三行代码
Long categoryId=dishDTO.getCategoryId();
String key="dish_"+categoryId;
cleanCache(key);
return Result.success();
}
/**
* 菜品批量删除
* @param ids
* @return
*/@DeleteMapping
@ApiOperation("菜品批量删除")
public Result delete(@RequestParam List<Long> ids){
log.info("菜品批量删除:{}",ids);
dishService.deleteBatch(ids);
//添加这一行
cleanCache("dish_*");
return Result.success();
}
/**
* 修改菜品
* @param dishDTO
* @return
*/
@PutMapping
@ApiOperation("修改菜品")
public Result update(@RequestBody DishDTO dishDTO) {
log.info("修改菜品:{}",dishDTO);
dishService.updateWithFlavor(dishDTO);
//添加这行
cleanCache("dish_*");
return Result.success();
}
2.3Spring Cache
Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能。
Spring Cache 提供了一层抽象,底层可以切换不同的缓存实现,例如: EHCache Caffeine Redis。
常用注解:
|
注解 |
说明 |
|
@EnableCaching |
开启缓存注解功能,通常加在启动类上 |
|
@Cacheable |
在方法执行前先查询缓存中是否有数据,如果有数据,则直接返回缓存数据; 如果没有缓存数据,调用方法并将方法返回值放到缓存中 |
|
@CachePut |
将方法的返回值放到缓存中 |
|
@CacheEvict |
将一条或多条数据从缓存中删除 |
3.缓存套餐
3.1导入各个类
在sky-server包下导入
<!-- 导入Spring Data Redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 导入 Spring Cache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
然后要在sky-server包下的启动类SkyApplication类上加如下注解:
@EnableCaching
首先是在controller/user包下的SetmealController类中的list方法上加如下注解:
@Cacheable(cacheNames="setmealCache",key="#categoryId")
然后是在controller/admin包下的SetmealController类中的save方法上加如下注解:
@CacheEvict(cacheNames="setmealCache",key="#setmealDTO.categoryId")
最后是在controller/admin包下的SetmealController类中的update、delete、startOrStop方法上加如下注解:
@CacheEvict(cacheNames = "setmealCache",allEntries = true)
4.添加购物车
4.1ShoppingCartController类(controller/user下创建)
@RestController
@RequestMapping("/user/shoppingCart")
@Slf4j
@Api(tags="C端购物车相关接口")
public class ShoppingCartController {
@Autowired
private ShoppingCartService shoppingCartService;
@PostMapping("/add")
@ApiOperation("添加购物车")
public Result add(@RequestBody ShoppingCartDTO shoppingCartDTO){
log.info("添加购物车,商品信息为:{}",shoppingCartDTO);
shoppingCartService.addShoppingCart(shoppingCartDTO);
return Result.success();
}
}
4.2ShoppingCartService类(Service下创建)
package com.sky.service;
import com.sky.dto.ShoppingCartDTO;
import com.sky.entity.ShoppingCart;
public interface ShoppingCartService {
/**
* 添加购物车
* @param shoppingCartDTO
*/
void addShoppingCart(ShoppingCartDTO shoppingCartDTO);
//判断当前加入购物车中的商品是否已经存在了
//如果已经存在,只需要数量+1
//如果不存在,则需要插入一条购物车数据
}
4.3ShoppingCartMapper类
package com.sky.mapper;
import com.sky.entity.ShoppingCart;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Update;
import java.util.List;
@Mapper
public interface ShoppingCartMapper {
/**
* 条件查询
* @param shoppingCart
* @return
*/
List<ShoppingCart> list(ShoppingCart shoppingCart);
/**
* 更新商品数量
* @param shoppingCart
*/
@Update("update shopping_cart set number=#{number} where id=#{id}")
void updateNumberById(ShoppingCart shoppingCart);
/**
* 插入数据到购物车
* @param shoppingCart
*/
@Insert("insert into shopping_cart(name, image, user_id, dish_id, setmeal_id, dish_flavor, number, amount, create_time) " +
"VALUES(#{name},#{image},#{userId},#{dishId},#{setmealId},#{dishFlavor},#{number},#{amount},#{createTime}) ")
void insert(ShoppingCart shoppingCart);
}
4.4ShoppingCartMapper.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.ShoppingCartMapper">
<select id="list" parameterType="ShoppingCart" resultType="ShoppingCart">
select * from shopping_cart
<where>
<if test="userId != null">
and user_id = #{userId}
</if>
<if test="dishId != null">
and dish_id = #{dishId}
</if>
<if test="setmealId != null">
and setmeal_id = #{setmealId}
</if>
<if test="dishFlavor != null">
and dish_flavor = #{dishFlavor}
</if>
</where>
order by create_time desc </select>
</mapper>
5.查看购物车&清空购物车
5.1ShoppingCartController类
/**
* 查看购物车
* @return
*/
@ApiOperation("查看购物车")
@GetMapping("/list")
public Result<List<ShoppingCart>> list() {
List<ShoppingCart> list = shoppingCartService.showShoppingCart();
return Result.success(list);
}
/**
** 清空购物车
** @return
**/
@DeleteMapping("/clean")
@ApiOperation("清空购物车")
public Result<String> clean(){
shoppingCartService.cleanShoppingCart();
return Result.success();
}
5.2ShoppingCartService类
/**
* 清空购物车
*/
void cleanShoppingCart();
/**
* 查看购物车
* @return
*/
List<ShoppingCartDTO> showShoppingCart();
5.3ShoppingCartServiceImpl类
/**
**
* 清空购物车
* */
public void cleanShoppingCart() {
shoppingCartMapper.deleteByUserId(BaseContext.getCurrentId());
}
/**
* 查看购物车
*/
@Override
public List<ShoppingCart> showShoppingCart() {
Long userId = BaseContext.getCurrentId();
ShoppingCart shoppingCart = ShoppingCart.builder()
.userId(userId)
.build();
List<ShoppingCart> list = shoppingCartMapper.list(shoppingCart);//只需要传userid即可
return list;
}
更多推荐
所有评论(0)