用户注册实现
编辑UserController
@RequestMapping("/user/doRegister")
@ResponseBody
public SysResult doRegister(User user) {
userService.doRegister(user);
return SysResult.success();
}
编辑UserService
@Service
public class DubboUserServiceImpl implements DubboUserService{
@Autowired
private UserMapper userMapper;
@Override
@Transactional //控制事务
public void doRegister(User user) {
//1.密码加密 md5 md5hash shiro框架
byte[] bytes = user.getPassword().getBytes();
String md5Pass = DigestUtils.md5DigestAsHex(bytes);
user.setPassword(md5Pass).setEmail(user.getPhone())
.setCreated(new Date()).setUpdated(user.getCreated());
userMapper.insert(user);
}
}
用户单点登陆
编辑UserController
/**
* Cookie数据的共享问题:
* 原则:Cookie根据不同的域名,展现的数据(权限)不同
* www.jd.com 默认条件下浏览器中只能看到 www.jd.com的cookie信息.
* www.baidu.com 默认条件下只能看到www.baidu.com的cookie信息.
*
* cookie.setDomain("jd.com");
* xxxx.jd.com全部域名可以实现cookie数据共享
*
* @param user
* @return
*/
@RequestMapping("/doLogin")
@ResponseBody
public SysResult doLogin(User user,HttpServletResponse response) {
//1.调用远程jt-sso服务器
String uuid = userService.doLogin(user);
//2.检验uuid是否为null
if(StringUtils.isEmpty(uuid)) {
//说明后台服务器校验不通过.
return SysResult.fail();
}
//3.用户登陆正常,之后需要将用户数据写入cookie中
Cookie cookie = new Cookie("JT_TICKET", uuid);
cookie.setMaxAge(7*24*60*60); //7天超时
cookie.setDomain("jt.com"); //设定cookie数据共享
//www.jd.com/find 可以获取
//www.jd.com/aaa/find 可以获取的!!
cookie.setPath("/"); //当前cookie在根目录中有效
response.addCookie(cookie);
//4.返回正确的数据
return SysResult.success();
}
编辑UserService
/**
* 1.根据用户信息查询数据库,检查是否有效
* 2.根据查询结果
* null: 表示用户名和密码错误.
* 有结果: 执行单点登陆的业务流程.
*/
@Override
public String doLogin(User user) { //UUID
//密码加密
String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
queryWrapper.eq("username", user.getUsername())
.eq("password", md5Pass);
//根据username和password获取用户信息
User userDB = userMapper.selectOne(queryWrapper);
//判断数据是否有效
if(userDB == null) {
//根据用户名和密码查询,没有结果
return null;
}
//如果程序执行到这里,说明用户的查询没有错,可以进行单点登陆操作
String key = UUID.randomUUID().toString();
//不安全:userDB包含了用户的全部记录信息, 由于userJSON保存到第三方存储,最好
//将敏感数据去除(脱敏处理)
userDB.setPassword("123456");
String userJSON = ObjectMapperUtil.toJSON(userDB);
jedisCluster.setex(key, 7*24*60*60, userJSON);
return key;
}
用户信息回显
编辑jt-sso UserController
/**
*JSONP调用
* 根据ticket信息查询userJSON数据
*/
@GetMapping("/query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket,String callback) {
String userJSON = jedisCluster.get(ticket);
//判断当前redis中是否有数据
if(StringUtils.isEmpty(userJSON)) {
return new JSONPObject(callback, SysResult.fail());
}else {
//证明用户已经登陆
SysResult sysResult = SysResult.success(userJSON);
return new JSONPObject(callback,sysResult);
}
}
用户退出
/**
* 实现用户退出,重定向到系统首页
* http://www.jt.com/user/logout.html
* 思考:
* 1.获取cookie数据. JT_TICKET
* 2.获取ticket信息 删除redis数据
* 3.删除cookie记录
* 4.重定向到系统首页
*
*/
@RequestMapping("/logout")
public String logout(HttpServletRequest request,HttpServletResponse response) {
Cookie[] cookies = request.getCookies();
if(cookies !=null && cookies.length>0) {
for (Cookie cookie : cookies) {
if("JT_TICKET".equals(cookie.getName())) {
String ticket = cookie.getValue();
//删除redis数据
jedisCluster.del(ticket);
//删除cookie时需要重新为cookie赋值,否则删除失效
cookie.setMaxAge(0); //立即删除
cookie.setDomain("jt.com"); //设定cookie数据共享
cookie.setPath("/"); //当前cookie在根目录中有效
response.addCookie(cookie);
break;
}
}
}
return "redirect:/";
}
购物车业务
编辑POJO
@TableName("tb_cart")
@Data
@Accessors(chain=true)
public class Cart extends BasePojo{
@TableId(type=IdType.AUTO)
private Long id;
private Long userId;
private Long itemId;
private String itemTitle; //商品标题
private String itemImage; //商品图片
private Long itemPrice; //商品价格
private Integer num; //数量
}
编辑CartController
@Controller //1
@RequestMapping("/cart")
public class CartController {
@Reference(check=false)
private DubboCartService cartService;
/**
* 2.根据userId获取购物车数据
* 页面取值:${cartList}
* @return
*/
@RequestMapping("/show")
public String show(Model model) {
Long userId = 7L;
List<Cart> cartList = cartService.findCartListByUserId(userId);
model.addAttribute("cartList", cartList);
return "cart";
}
}
编辑CartService
@Service
public class DubboCartServiceImpl implements DubboCartService {
@Autowired
private CartMapper cartMapper;
@Override
public List<Cart> findCartListByUserId(Long userId) {
QueryWrapper<Cart> queryWrapper = new QueryWrapper<Cart>();
queryWrapper.eq("user_id", userId);
return cartMapper.selectList(queryWrapper);
}
}
商品数量修改
编辑CartController
/**
* 完成商品数量的修改
* restFul规则说明: 如果参数名称与属性的名称一致,则可以使用对象接收
*/
@RequestMapping("/update/num/{itemId}/{num}")
@ResponseBody
public SysResult updateCartNum(Cart cart) {
Long userId = 7L;
cart.setUserId(userId);
cartService.updateCartNum(cart);
return SysResult.success();
}
编辑CartService
/**
* entity 修改的数据信息
* updateWrapper:修改数据的条件
*/
@Override
@Transactional //控制事务
public void updateCartNum(Cart cart) {
Cart cartTemp = new Cart();
cartTemp.setNum(cart.getNum())
.setUpdated(new Date());
UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("user_id", cart.getUserId())
.eq("item_id", cart.getItemId());
cartMapper.update(cartTemp, updateWrapper);
}
商品删除
编辑CartController
/**
* 业务需求:根据itemId和userId删除购物车
*
*/
@RequestMapping("/delete/{itemId}")
public String deleteCart(Cart cart) {
Long userId = 7L;
cart.setUserId(userId);
cartService.deleteCart(cart);
return "redirect:/cart/show.html"; //重定向到购物车列表页面
}
编辑CartService
@Override
public void deleteCart(Cart cart) {
//根据对象中不为null的属性来充当where条件.
QueryWrapper<Cart> wrapper = new QueryWrapper<Cart>(cart);
cartMapper.delete(wrapper);
}
购物车新增
编辑CartController
/**
* 购物车新增
*/
@RequestMapping("/add/{itemId}")
public String saveCart(Cart cart) {
Long userId = 7L;
cart.setUserId(userId);
cartService.saveCart(cart);
return "redirect:/cart/show.html"; //重定向到购物车列表页面
}
编辑CartService
/**
* 思路:
* 1.根据userId和itemId查询数据库.
* 2.如果查询没有结果,则做新增操作.
* 3.如果查询有结果,则做更新操作.
*/
@Override
@Transactional //控制事务
public void saveCart(Cart cart) {
QueryWrapper<Cart> queryWrapper = new QueryWrapper<Cart>();
queryWrapper.eq("user_id", cart.getUserId())
.eq("item_id", cart.getItemId());
Cart cartDB = cartMapper.selectOne(queryWrapper);
//判断是否有值
if(cartDB == null) {
cart.setCreated(new Date())
.setUpdated(cart.getCreated());
cartMapper.insert(cart);
}else {
//更新操作
int num = cart.getNum() + cartDB.getNum();
//cartDB.setNum(num).setUpdated(new Date());
//UPDATE tb_cart SET user_id=?, item_id=?, item_title=?, item_image=?, item_price=?, num=?, created=?, updated=? WHERE id=?
//UPDATE tb_cart SET num=?,updated=? WHERE id=?
Cart cartTemp = new Cart();
cartTemp.setNum(num).setUpdated(new Date());
UpdateWrapper<Cart> updateWrapper = new UpdateWrapper<Cart>();
updateWrapper.eq("id", cartDB.getId());
cartMapper.update(cartTemp, updateWrapper);
}
}
项目权限设计
当用户点击购物车时需要校验用户是否登陆.如果用户没有登陆,则重定向到登陆页面.如果用户已经登陆,则放行请求.
拦截器工作流程
编辑拦截器
@Component
public class UserInterceptor implements HandlerInterceptor{
@Autowired
private JedisCluster jedisCluster;
/**
* boolean: true 拦截器放行
* false 拦截器拦截 一般配合重定向的方式使用.
*
* 拦截器的业务策略:
* 如果用户已经登陆则放行,如果未登录则拦截
*
* 思路:判断用户登陆的业务逻辑
* 1.获取用户的Cookie记录
* 2.获取JT_TICKET的值.
* 3.查询redis
* null: false
* !null: true
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//根据cookie获取value结果
String cookieValue = CookieUtils.getValue(request, "JT_TICKET");
//判断value是否有值
if(!StringUtils.isEmpty(cookieValue)) {
//判断redis中是否有该记录.
if(jedisCluster.exists(cookieValue)) {
String key = cookieValue;
String userJSON = jedisCluster.get(key);
User user = ObjectMapperUtil.toObject(userJSON, User.class);
//将数据保存到request对象中
request.setAttribute("JT_USER", user);
//如果有特殊的需求,可以利用session临时保存数据.
//request.getSession().setAttribute(name, value);
//用户已经登陆.予以放行
return true;
}
}
response.sendRedirect("/user/login.html");
return false; //表示拦截
}
/**
* 结构完整!!!!
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
//业务处理完成之后,将用户信息删除.
request.removeAttribute("JT_USER");
}
}
动态获取UserId显示购物车信息
@RequestMapping("/show")
public String show(Model model,HttpServletRequest request) {
User user = (User) request.getAttribute("JT_USER");
Long userId = user.getId();
List<Cart> cartList = cartService.findCartListByUserId(userId);
model.addAttribute("cartList", cartList);
return "cart";
}
订单业务
编辑OrderController
@Controller
@RequestMapping("/order")
public class OrderController {
private static final String USERNAME = "JT_USER";
@Reference(check=false)
private DubboCartService cartService;
//http://www.jt.com/order/create.html
@RequestMapping("/create")
public String create(HttpServletRequest request,Model model) {
//动态获取用户的购物车记录 ${carts}
User user = (User) request.getAttribute(USERNAME);
Long userId = user.getId();
List<Cart> cartList = cartService.findCartListByUserId(userId);
request.setAttribute("carts", cartList);
return "order-cart";
}
}
编辑OrderController.完成订单入库.
/**
* 完成订单入库操作
* url:http://www.jt.com/order/submit
* 参数:利用order对象进行数据封装
* 返回值结果:SysResult对象(orderId)
*/
@RequestMapping("/submit")
@ResponseBody
public SysResult submit(Order order,HttpServletRequest request) {
User user = (User) request.getAttribute("JT_USER");
Long userId = user.getId();
order.setUserId(userId);
String orderId = orderService.saveOrder(order);
return SysResult.success(orderId);
}
编辑OrderService
@Service
public class OrderServiceImpl implements DubboOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private OrderShippingMapper orderShippingMapper;
@Autowired
private OrderItemMapper orderItemMapper;
@Transactional //事务控制
@Override
public String saveOrder(Order order) {
//1.定义orderId 登录用户id+当前时间戳'
String orderId = ""+order.getUserId()+System.currentTimeMillis();
Date date = new Date();
//2.实现订单表入库操作
order.setOrderId(orderId)
.setStatus(1)
.setCreated(date)
.setUpdated(date);
orderMapper.insert(order);
System.out.println("订单入库成功!!!!");
//3.订单物流入库
OrderShipping shipping = order.getOrderShipping();
shipping.setOrderId(orderId)
.setCreated(date)
.setUpdated(date);
orderShippingMapper.insert(shipping);
System.out.println("订单物流入库成功!!!!");
//4.入库订单商品
List<OrderItem> ordetItems = order.getOrderItems();
for (OrderItem orderItem : ordetItems) {
orderItem.setOrderId(orderId)
.setCreated(date)
.setUpdated(date);
orderItemMapper.insert(orderItem);
}
System.out.println("订单商品入库成功!!!!!");
return orderId;
}
}
订单查询实现
编辑OrderController
/**
* 实现订单查询
* url:http://www.jt.com/order/success.html?id=71588226717472
* 页面参数分析: ${order.orderId} 根据id查询订单信息.
* 要求实现3张表查询 order对象!!!!
*/
@RequestMapping("/success")
public String findOrderById(String id,Model model) {
//根据id查询订单信息.
Order order = orderService.findOrderById(id);
model.addAttribute("order", order);
return "success";
}
编辑OrderService
//实现3张表数据查询.
@Override
public Order findOrderById(String id) {
//想使用一个数据库链接,查询3张表数据!!!
Order order = orderMapper.selectById(id);
OrderShipping shipping = orderShippingMapper.selectById(id);
QueryWrapper<OrderItem> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("order_id", id);
List<OrderItem> list = orderItemMapper.selectList(queryWrapper);
return order.setOrderShipping(shipping).setOrderItems(list);
}
订单超时处理
引入jar包
<!--添加Quartz的支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
配置类介绍
@Configuration
public class OrderQuartzConfig {
//定义任务详情
@Bean
public JobDetail orderjobDetail() {
//指定job的名称和持久化保存任务
return JobBuilder
.newJob(OrderQuartz.class) //指定一个全新的任务
.withIdentity("orderQuartz") //指定任务名称
.storeDurably()
.build(); //任务创建 封装为JobDetail对象
}
//定义触发器
@Bean
public Trigger orderTrigger() {
/*SimpleScheduleBuilder builder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMinutes(1) //定义时间周期
.repeatForever();*/
//定义调度器 指定任务的执行的时间
CronScheduleBuilder scheduleBuilder
= CronScheduleBuilder.cronSchedule("0 0/1 * * * ?");
return TriggerBuilder
.newTrigger()
.forJob(orderjobDetail())
.withIdentity("orderQuartz")
.withSchedule(scheduleBuilder).build();
}
}
指定定时任务
定时任务每隔1分钟执行一次超时订单的处理.
//准备订单定时任务
@Component
public class OrderQuartz extends QuartzJobBean{
@Autowired
private OrderMapper orderMapper;
/**
* 业务需求:如果用户30分钟没有支付,则将订单的状态由1(未支付)改为6(交易关闭)
* 超时判定: now-created > 30分钟
* created < now-30 timeout
*
* Sql:update tb_order set status=6,updated=#{date}
* where status=1 and created < now-30
*/
@Override
@Transactional
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
//1.实例化工具API对象 获取当前时间
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MINUTE, -30);
Date timeOut = calendar.getTime();
Order order = new Order();
order.setStatus(6).setUpdated(new Date());
UpdateWrapper<Order> updateWrapper = new UpdateWrapper<>();
updateWrapper.eq("status", 1)
.lt("created", timeOut);
orderMapper.update(order, updateWrapper);
System.out.println("定时任务执行成功!!!!!");
}
}