目录
文章目录
- 目录
- 购物车
- ObjectMapper对象和JSON转换工具类
- 判断用户是否登录
- 拦截器(AOP)
- 在web服务器config配置拦截器拦截策略
- UserInterceptor自定义拦截器
- spring整合redis集群
- 添加redis.properties配置文件
- 在common工具jar的config配置redis
- 购物车DubboCartServiceImpl
- redis.properties添加card
- redis配置
- 数据结构选择
- 用hash类型
- 单点登陆
- sso服务器添加DubboUserServiceImpl
购物车
ObjectMapper对象和JSON转换工具类
public class JSONUtils {
private static final ObjectMapper MAPPER = new ObjectMapper();
//将对象转化为JSON
public static String toJSON(Object target){
try {
return MAPPER.writeValueAsString(target);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
//将JSON转化为对象
public static <T> T toObject(String json,Class<T> targetClass){
try {
return MAPPER.readValue(json, targetClass);
} catch (JsonProcessingException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
判断用户是否登录
拦截器(AOP)
在web服务器config配置拦截器拦截策略
@Configuration //标识一个配置类
public class MvcConfigurer implements WebMvcConfigurer{
//注入拦截器
@Autowired
private UserInterceptor userInterceptor;
//配置拦截器拦截策略
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(userInterceptor)
//拦截cart、order的所有请求
.addPathPatterns("/cart/**","/order/**");
}
}
UserInterceptor自定义拦截器
自定义类实现HandlerInterceptor接口,重写放法:
preHandle
- 调用时间:Controller方法处理之前
postHandle
- 调用前提:preHandle返回true
- Controller方法处理完之后,DispatcherServlet进行视图的渲染之前,也就是说在这个方法中你可以对ModelAndView进行操作
afterCompletion
- 调用前提:preHandle返回true
- DispatcherServlet进行视图的渲染之后,多用于清理资源
@Component //表示将此类标记为Spring容器中的一个Bean
public class UserInterceptor implements HandlerInterceptor{
@autowired
private JedisCluster jedis;//注入redis集群对象
//preHandle 处理之前调用
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception{
String ticket = null; //cookie存放的令牌
//判断cookie中是否有记录
Cookie[] cookies = request.getCookies();
if(cookies!=null&&cookies.length>0){
for(Cookie cookie:cookies){
if("JH_TICKET".equals(cookie.getName())){
//有令牌直接取出value(存放的是uuid,单点登陆放到redis的key(value是userJSON))
ticket = cookie.getValue();
break;
}
}
}
//判断ticket是否有效
if(!StringUtils.isEmpty(ticket)){
if(jedis.exists(ticket)){
//去除redis中以ticket为key的value
String userJSON = jedis.get(ticket);
User user = ObjectMapperUtil.toObject(userJSON,User.class);
//存到ThreadLocal对象(同线程变量)
UserThreadLocal.set(user);
return true; //去执行controller
}
}
//未登陆,重定向到登陆页面
response.sendRedirect("/userLogin.thml");
return false; //不执行controller
}
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception{
//为了防止内存泄露,将多余的数据删除
//request.removeAttribute("JH_USER");
UserThreadLocal.remove();
}
}
spring整合redis集群
添加redis.properties配置文件
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002...
在common工具jar的config配置redis
@configuration //标识一个配置类
//加载redis配置文件
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig{
//获取redis配置文件
@Value("${redis.nodes}")
private String nodes;
//在 getJedisCluster() 方法上添加 @Bean 注解则会往 Spring 容器中添加一个名为 JedisCluster 的 Bean,该 Bean 即为方法的返回值。
@Bean
public JedisCluster getJedisCluster(){
//set集合保存redis集群的每个节点(HostAndPort用于创建集群对象)
Set<HostAndPort> nodeSet = new HashSet<>();
//切割redis.nodes得到redis节点array
String[] nodeArray = nodes.split(",");
for(String node:nodeArray){
String host = node.split(":")[0];//
int port = Integer.parseInt(node.split(":")[1]);
nodeSet.add(new HostAndPort(host,port));
}
//返回一个JedisCluster交给spring容器管理
return new JedisCluster(nodeSet);
}
}
购物车DubboCartServiceImpl
redis.properties添加card
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002...
redis.card=card
//dubbo 的service(调用服务超时时间)
@Service(timeout = 3000)
public class DubboCartServiceImpl implements DubboCartService{
@Autowired //注入redis集群
private JedisCluster jedis;
@Reference(check = false) //注入itemService
private DubboItemService dubboItemService;
@Value("${redis.card}")
private String CART_KEY;
//添加购物车
@Override
public SysResult addCart(Long userId,Long itemId,int num){
//判断购物车里是否存在此商品
Boolean hexists = jedis.hexists(CART_KEY":"+userId,itemId+"");
if(hexists){
//如果存在,取出redis里的Cart JSON信息
String json = jedis.hget(CART_KEY":"+userId,itemId+"");
Cart cart = JSONUtils.toPojo(json,Cart.class);
cart.setNum(cart.getNum()+num); //数量累加
//写回redis
jedis.hset(CART_KEY":"+userId,itemId+"",JSONUtils.toJSON(cart));
//给用户返回结果
return SysResult.success();
}
//如果不存在,根据商品id获取商品信息
Item item = null;
//从redis中获取
if(jedis.exists(itemId)){
String itemJSON = jedis.get(itemId);
item = JSONUtils.toObject(itemJSON,Item.class);
}
//从数据库直接获取
item = dubboItemService.selectItemByItemId(itemId);
if(item!=null)
return SysResult.fail();
//把商品信息存入redis购物车
Cart cart = new Cart();
cart.setItem(item).setNum(num);
jedis.hset(CART_KEY+":"+userId,itemId,JSONUtils.toJSON(cart));
return SysResult.success();
}
}
redis配置
使用redis缓存存放购物车信息.
注意:
redis是存在内存中的,默认RDB持久化策略(默认配置60s内有10000个key发生变化刷新一次镜像).为了防止数据丢失应手动开启AOF持久化策略(配置appendonly yes
)
数据结构选择
常用5种数据类型:string,hash,list,set,sorted set
用hash类型
命令 | 作用 |
hset key_name field_name value | 添加(field不存在创建,field存在覆盖value) |
hget key_name field_name | 获取(存在返回field,不存在返回 |
hexists key_name field_name | 判断key中指定field是否存在(存在1,不存在0) |
hlen key_name | 获取哈希表中字段的数量 |
单点登陆
sso服务器添加DubboUserServiceImpl
@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService{
@Autowired //注入userMapper
private UserMapper userMapper;
@Autowired //注入redis集群
private JedisCluster jedis;
@Override
public String doLogin(User user){
//根据userName获取数据库中的用户对象
User userDB = userMapper.selectByKey(user.getUserName());
//没有直接返回
if(userDB==null)
return null;
//用户输入的密码md5摘要(用于判断密码是否正确)
String md5Pass = MD5Utils.md5Digest(user.getPassword());
//判断密码是否正确
if(MD5Utils.doSal(userDB.getPassword())!=md5Pass)
return null;
//登陆成功user JSON 存如redis(key=uuid,7天有效期,value=userJSON)
String uuid = UUID.randomUUID().toString().replace("-","");
userDB.setPassword(""); //去除重要信息
jedis.setex(uuid,7*24*60*60,JSONUtils.toJSON(userDB));
}
}