SOA dubbo框架应用

1 完成京淘单点登录业务实现

1.1 用户注册实现

1.1.1 业务需求说明

说明: 当用户点击新增按钮时,应该将数据由jt-web服务器,传递给jt-sso项目完成入库操作.同时返回有效信息进行校验.
在这里插入图片描述

1.1.2 页面分析

1).url分析
在这里插入图片描述
2).参数说明
在这里插入图片描述
3). 检查页面JS
在这里插入图片描述

1.1.3 编辑JT-WEB UserController

 /**
     * 完成用户注册操作
     * 1.url地址:http://www.jt.com/user/doRegister
     * 2.参数:   password: admin123
     *           username: admin12332412341234
     *           phone: 13111112227
     * 3.返回值:  SysResult对象
     */
    @RequestMapping("/doRegister")
    @ResponseBody   //将返回值结果转化为JSON
    public SysResult saveUser(User user){

        userService.saveUser(user);
        return SysResult.success();
    }

1.1.4 编辑JT-SSO UserService

package com.jt.service;

import com.alibaba.dubbo.config.annotation.Service;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;
import sun.security.provider.MD5;

@Service
public class DubboUserServiceImpl implements DubboUserService{

    @Autowired
    private UserMapper userMapper;

    /**
     * 业务:
     *  1.将密码进行加密处理
     *  2. 邮箱暂时用电话代替
     * @param user
     */
    @Override
    public void saveUser(User user) {

        byte[] bytes = user.getPassword().getBytes();
        //利用Spring工具API进行加密操作
        String md5Pass = DigestUtils.md5DigestAsHex(bytes);
        user.setPassword(md5Pass).setEmail(user.getPhone());
        userMapper.insert(user);
    }
}


1.2 用户实现单点登录

1.2.1 业务需求

要求: 用户只需要登录一次,则可以在任意的服务器享受免密登录.有效期为30天.

sso介绍:
单点登录(SingleSignOn,SSO),就是通过用户的一次性鉴别登录。当用户在身份认证服务器上登录一次以后,即可获得访问单点登录系统中其他关联系统和应用软件的权限,同时这种实现是不需要管理员对用户的登录状态或其他信息进行修改的,这意味着在多个应用系统中,用户只需一次登录就可以访问所有相互信任的应用系统。这种方式减少了由登录产生的时间消耗,辅助了用户管理,是目前比较流行的 [1]

1.2.2 单点登录实现原理

在这里插入图片描述
单点登录实现步骤:
1.用户通过用户名和密码访问jt-web服务器.
2.JT-WEB服务器通过JT-SSO校验用户名和密码是否正确.
3.如果用户名和密码正确,则将数据保存到redis中. TICKET密钥:USERJSON,之后将密钥返回给用户即可.
4.JT-WEB服务器将密钥信息保存到用户的Cookie中 并且设定Cookie的共享/有效时间.

1.2.3 登录页面分析

1).url分析
在这里插入图片描述
2).参数分析
在这里插入图片描述
3).页面JS
在这里插入图片描述

1.2.4 编辑UserController

 /**
     * 业务需求:
     *   实现用户单点登录操作
     *   1.url地址:http://www.jt.com/user/doLogin?r=0.43530970885614617
     *   2.请求参数:  username: asdasdfas
     *                password: asdfasdfa
     *   3.返回值结果: SysResult对象
     *
     * 实现Cookie数据存储
     *  1.获取用户名和密码进行数据校验
     *  2.获取后端的密钥信息  非空????
     *  3.如果一切正常,则将数据存储到Cookie中. 路径/有效期/共享问题
     *
     * 关于Cookie说明:
     *      1.cookie只能看到自己域名下的cookie   私有的.
     *      2.setPath说明
     *          setPath("/") 一般都是/  读取cookie权限的设定,根目录中的请求 读取cookie
     *          setPath("/user") url地址路径/user下时才能获取cookie信息.
     *          url1: http://www.jt.com/findUser;
     *          url2: http://www.jt.com/user/findUser;
     *
     */
    @RequestMapping("/doLogin")
    @ResponseBody
    public SysResult userLogin(User user, HttpServletResponse response){
        String ticket = userService.findUserByUP(user);
        if(!StringUtils.hasLength(ticket)){
            //如果数据为null则表示用户名和密码错误...
            return SysResult.fail();
        }

        //需要将数据保存到cookie中
        Cookie cookie = new Cookie("JT_TICKET", ticket);
        cookie.setPath("/");
        cookie.setMaxAge(7*24*60*60); //设定有效期 7天有效 单位秒
        cookie.setDomain("jt.com");   //主要域名中由jt.com则可以共享数据
        response.addCookie(cookie);   //将数据写入客户端
        return SysResult.success();
    }

1.2.5 编辑UserService

/**
     * 1.校验用户名和密码是否正确  不存在直接返回null
     * 2.动态生成密钥   将用户信息转化为JSON
     * 3.将数据保存到redis中 7天有效.
     * 4.返回密钥ticket信息.
     * @param user
     * @return
     */
    @Override
    public String findUserByUP(User user) {
        String md5Pass =
                DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
        user.setPassword(md5Pass);
        //1.根据对象中不为null的属性当做where条件
        QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
        User userDB = userMapper.selectOne(queryWrapper);

        //2.判断对象是否有值
        if(userDB==null){
            return null;
        }

        //3.表示用户名和密码正确 开启单点登录操作
        String ticket = UUID.randomUUID()
                        .toString().replace("-", "");
        //转化之前应该将数据进行脱敏处理
        userDB.setPassword("123456");
        String userJSON = ObjectMapperUtil.toJSON(userDB);

        //4.将数据保存到redis中
        jedisCluster.setex(ticket, 7*24*60*60, userJSON);
        return ticket;
    }

1.2.6 效果测试

在这里插入图片描述

1.3 用户数据回显

1.3.1 业务分析

如果用户登录成功之后,则通过cookie数据利用JSONP跨域方式,实现数据的动态获取.

1.3.2 页面URL分析

1).页面URL分析
在这里插入图片描述
2).检查页面JS
在这里插入图片描述

1.3.3 编辑JT_SSO UserController

/**
     * 跨域请求:完成用户信息获取
     * URL网址:  http://sso.jt.com/user/query/dca70b16a1c54aea9ebb0b27621250de?callback=jsonp1608021961735&_=1608021961777
     * 参数:    参数1: ticket信息    参数2:callback
     * 返回值:   SysResult对象(用户数据......)
     */
    @RequestMapping("/query/{ticket}")
    public JSONPObject findUserByTicket(@PathVariable String ticket,
                                        String callback){
        //如何获取用户信息?  从redis中获取数据
        if(jedisCluster.exists(ticket)){
            String userJSON = jedisCluster.get(ticket);
            SysResult sysResult = SysResult.success(userJSON);
            return new JSONPObject(callback, sysResult);
        }else{
            return new JSONPObject(callback, SysResult.fail());
        }
    }

2. 完成用户退出操作

2.1 业务说明

1).当用户点击退出按钮时,应该重定向到系统首页
2).删除redis中的数据
3).删除Cookie中的数据

2.2 编辑UserController

 /**
     * 完成用户退出操作
     * 1.重定向到系统首页
     * 2.要求删除redis中的数据  K-V结构  先获取key
     * 3.动态获取Cookie中的数据
     * 4.删除Cookie中的数据
     * url地址: http://www.jt.com/user/logout.html
     *
     */
    @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.setMaxAge(0); //0 立即删除  -1 关闭浏览器之后删除
                  cookie.setPath("/");
                  cookie.setDomain("jt.com");
                  response.addCookie(cookie);
              }
          }
      }

        return "redirect:/";
    }

2.3 封装工具API

作用: API主要的作用 简化Cookie调用的过程. 1.获取Cookie对象 2.可以根据cookieName 获取cookie的值 3.新增cookie 删除cookie

public class CookieUtil {

    //1.获取cookie对象
    public static Cookie getCookie(HttpServletRequest request,String cookieName){
        Cookie[] cookies = request.getCookies();
        if(cookies !=null && cookies.length>0){
            for(Cookie cookie : cookies){
               if(cookieName.equals(cookie.getName())){
                   return cookie;
               }
            }
        }
        return null;
    }

    //2.获取Cookie值
    public static String getCookieValue(HttpServletRequest request,String cookieName){
        Cookie cookie = getCookie(request,cookieName);
        return cookie ==null?null:cookie.getValue();
    }

    //3.新增Cookie/删除Cookie写法
    public static void addCookie(HttpServletResponse response,String cookieName,String cookieValue,String path,String domain,Integer seconds){
        Cookie cookie = new Cookie(cookieName,cookieValue);
        cookie.setPath(path);
        cookie.setDomain(domain);
        cookie.setMaxAge(seconds);
        response.addCookie(cookie);
    }
}

1.4 重构UserController 完成退出操作

 /**
     * 完成用户退出操作
     * 1.重定向到系统首页
     * 2.要求删除redis中的数据  K-V结构  先获取key
     * 3.动态获取Cookie中的数据
     * 4.删除Cookie中的数据
     * url地址: http://www.jt.com/user/logout.html
     *
     */
    @RequestMapping("/logout")
    public String logout(HttpServletRequest request,HttpServletResponse response){
        String ticket = CookieUtil.getCookieValue(request, JT_TICKET);
        if(StringUtils.hasLength(ticket)){
            //1.删除redis
            jedisCluster.del(ticket);
            //2.删除cookie
            CookieUtil.addCookie(response,JT_TICKET,
                    "", "/", "jt.com", 0);
        }
        return "redirect:/";



      /*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.setMaxAge(0); //0 立即删除  -1 关闭浏览器之后删除
                  cookie.setPath("/");
                  cookie.setDomain("jt.com");
                  response.addCookie(cookie);
              }
          }
      }

        return "redirect:/";
        */
    }

3. 实现商品数据展现

3.1 构建JT-MANAGE为服务生产者

3.1.1 定义接口的实现

在这里插入图片描述

3.1.2 编辑YML配置文件

在这里插入图片描述

3.1.3编辑服务消费者

在这里插入图片描述

3.2 实现商品动态获取

3.2.1 业务需求

1.当用户点击商品按钮时,跳转到商品的展现页面 item.jsp
2.根据itemId号 查询item表/itemDesc表
3.将数据在页面中进行展现
在这里插入图片描述

3.2.2 编辑ItemController

@Controller
public class ItemController {

    //启动时是否校验有服务提供者
    @Reference(check=false)
    private DubboItemService itemService;

    /**
     * 根据商品ID查询商品信息
     * 1.URL地址:http://www.jt.com/items/562379.html
     * 2.参数:   562379 restFul风格
     * 3.返回值: String
     * 4.页面取值操作
     *      ${item.title }          获取商品信息   同步取值
     *      ${itemDesc.itemDesc }   获取商品详情信息
     */
    @RequestMapping("/items/{itemId}")
    public String findItemById(@PathVariable Long itemId, Model model){
        //1.获取商品相关信息
        Item item = itemService.findItemById(itemId);
        ItemDesc itemDesc = itemService.findItemDescById(itemId);

        //2.将数据传递到页面中
        model.addAttribute("item",item);
        model.addAttribute("itemDesc",itemDesc);

        //跳转到商品展现页面
        return "item";
    }

}

3.2.3 编辑ItemService

@Service(timeout = 3000)
public class DubboItemServiceImpl implements DubboItemService {

    @Autowired
    private ItemMapper itemMapper;
    @Autowired
    private ItemDescMapper itemDescMapper;


    @Override
    public Item findItemById(Long itemId) {
        return itemMapper.selectById(itemId);
    }

    @Override
    public ItemDesc findItemDescById(Long itemId) {
        return itemDescMapper.selectById(itemId);
    }
}

3.2.4 商品展现效果测试

在这里插入图片描述

3 购物车实现

3.1 新建Cat POJO对象

在这里插入图片描述

3.2 创建JT-CART项目

3.2.1 创建JT-CART项目

在这里插入图片描述

3.2.2 添加继承/依赖/插件

 <parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>


    <!--添加jar包文件依赖-->
    <dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--所有业务系统,必须添加build标签-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

3.2.3 构建Dubbo Cart项目

在这里插入图片描述

3.2.4 编辑YML配置文件

server:
  port: 8094
  servlet:
    context-path: /
spring:
  datasource:
    #引入druid数据源
    #type: com.alibaba.druid.pool.DruidDataSource
    #driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    #链接的是数据库代理
    #url: jdbc:mysql://192.168.126.129:8066/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
    username: root
    password: root

  mvc:
    view:
      prefix: /WEB-INF/views/
      suffix: .jsp
#mybatis-plush配置
mybatis-plus:
  type-aliases-package: com.jt.pojo
  mapper-locations: classpath:/mybatis/mappers/*.xml
  configuration:
    map-underscore-to-camel-case: true

logging:
  level: 
    com.jt.mapper: debug

#关于Dubbo配置
dubbo:
  scan:
    basePackages: com.jt    #指定dubbo的包路径
  application:              #应用名称
    name: provider-cart    #一个接口对应一个服务名称 如果是多个实现类则应用名称一致
  registry:
    address: zookeeper://192.168.126.129:2181?backup=192.168.126.129:2182,192.168.126.129:2183
  protocol:  #指定协议
    name: dubbo  #使用dubbo协议(tcp-ip)  web-controller直接调用sso-Service
    port: 20882  #每一个服务都有自己特定的端口 不能重复.

3.3 完成购物车列表展现

3.3.1 业务需求

当用户点击购物车按钮时,应该跳转到购物车列表页面中,要求根据userId 查询购物车列表数据.
同时跳转页面为 cart.jsp
在这里插入图片描述

3.3.2 编辑CartController

@Controller
@RequestMapping("/cart")
public class CartController {

    @Reference(check = false)
    private DubboCartService cartService;

    /**
     * 展现购物车列表数据
     * url地址:http://www.jt.com/cart/show.html
     * 参数:   必须获取userId=7L
     * 返回值:  cart.jsp
     * 页面取值参数: ${cartList}
     */
     @RequestMapping("/show")
     public String findCartList(Model model){
         long userId = 7L;   //暂时写死,后期维护
         List<Cart> cartList = cartService.findCartList(userId);
         model.addAttribute("cartList",cartList);
         return "cart";
     }
}

3.3.2 编辑CartService

@Service
public class DubboCartServiceImpl implements DubboCartService{

    @Autowired
    private CartMapper cartMapper;


    @Override
    public List<Cart> findCartList(long userId) {

        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", userId);
        return cartMapper.selectList(queryWrapper);
    }
}

3.3.3 页面效果展现

在这里插入图片描述

3.4 购物车数量修改

3.4.1 业务分析

1).页面URL分析
在这里插入图片描述
2).页面JS分析

$(".increment").click(function(){//+
			var _thisInput = $(this).siblings("input");
			_thisInput.val(eval(_thisInput.val()) + 1);
			$.post("/cart/update/num/"+_thisInput.attr("itemId")+"/"+_thisInput.val(),function(data){
				TTCart.refreshTotalPrice();
			});
		});

3.4.2 编辑CartController

 /**
     *  业务需求: 实现商品数量的更新操作
     *  url:http://www.jt.com/cart/update/num/1474391990/10
     *  参数: userId=7/itemId/num
     *  返回值: void
     *
     *  用法: 如果restFul参数名称与对象的属性名称一致,则可以使用对象的方式接收
     */
    @RequestMapping("/update/num/{itemId}/{num}")
    @ResponseBody //1.json返回   2.表示ajax请求结束
    public void updateCartNum(Cart cart){

        long userId = 7L;
        cart.setUserId(userId);
        cartService.updateCartNum(cart);
    }

3.4.3 编辑CartService

在这里插入图片描述

3.5 购物车新增操作

3.5.1 业务分析

说明: 当用户查询商品之后进行加购时,应该跳转(重定向)到购物车展现页面.
注意事项:
同一个用户重复添加相同的数据时,只修改商品的数量.
在这里插入图片描述

3.5.2 页面分析

1).页面URL分析
在这里插入图片描述
2).页面参数分析
在这里插入图片描述
3).页面JS分析
3.1 form标签
在这里插入图片描述
3.2 表单提交
在这里插入图片描述

3.5.3 编辑CartController

  /**
     * 完成购物车入库操作
     * url地址:http://www.jt.com/cart/add/1474391990.html
     * 参数:   cart form表单提交
     * 返回值: 重定向到购物车列表页面
     */
    @RequestMapping("/add/{itemId}")
    public String saveCart(Cart cart){

        long userId = 7L;
        cart.setUserId(userId);
        cartService.saveCart(cart);
        return "redirect:/cart/show.html";
    }

3.5.3 编辑CartService

//如果用户重复加购,则只做数量的修改
    //根据userId和itemId 判断数据是否有值
    @Override
    @Transactional
    public void saveCart(Cart cart) {
        QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", cart.getUserId());
        queryWrapper.eq("item_id", cart.getItemId());
        Cart cartDB = cartMapper.selectOne(queryWrapper);
        if(cartDB == null){ //表示数据库中没有记录,直接入库
            cartMapper.insert(cart);
        }else{  //数据库中有记录 只改数量
            int num = cart.getNum() + cartDB.getNum();
            //1.手写sql 2.简洁封装
            Cart cartTemp = new Cart();
            cartTemp.setId(cartDB.getId()).setNum(num);
            cartMapper.updateById(cartTemp);
        }
    }

3.6 实现购物车删除操作

3.6.1 业务分析

在这里插入图片描述

3.6.2 编辑CartController

 /**
     * 完成购物车删除操作
     * 1.url地址: http://www.jt.com/cart/delete/562379.html
     * 2.请求参数: 562379 itemId /userId
     * 3.返回值结果: 重定向到系统首页
     */
    @RequestMapping("/delete/{itemId}")
    public String deleteCarts(Cart cart){

        long userId = 7L;
        cart.setUserId(userId);
        cartService.deleteCarts(cart);
        return "redirect:/cart/show.html";
    }

3.6.3 编辑CartService

@Override
    public void deleteCarts(Cart cart) {

        cartMapper.delete(new QueryWrapper<>(cart));
    }

3.7 购物车权限控制

3.7.1 需求说明

当用户在没有登录的条件下不允许访问敏感业务. 购物车操作/订单操作等. 如何实现???
答:使用拦截器的机制
在这里插入图片描述

3.7.2 编辑配置类

在这里插入图片描述

3.7.3 编辑拦截器

package com.jt.interceptor;

import com.jt.util.CookieUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.JedisCluster;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component  //将拦截器交给spring容器管理
public class UserInterceptor implements HandlerInterceptor {

    private static final String JT_TICKET="JT_TICKET";

    @Autowired
    private JedisCluster jedisCluster;

    /**
     * 返回值说明:
     *      1.false  表示拦截  一般都要配合重定向的方式使用.
     *      2.true   表示放行
     *
     * 如何实现业务:
     *      判断用户是否登录:   Cookie数据  检查redis中的数据.
     *      重定向到系统登录页面.
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.校验Cookie中是否有结果
        Cookie cookie = CookieUtil.getCookie(request, JT_TICKET);

        //2.校验Cookie是否有效
        if(cookie != null){
            String ticket = cookie.getValue();
            if(StringUtils.hasLength(ticket)){
                //执行后续任务  校验redis中是否有结果
                if(jedisCluster.exists(ticket)){
                    //表示用户登录过  直接返回true
                    return true;
                }
            }
            //没有结果,则cookie数据有误,应该删除
            CookieUtil.addCookie(response, JT_TICKET, "", "/", "jt.com", 0);
        }

        //3.如果数据为空,则重定向到系统首页
        response.sendRedirect("/user/login.html");
        return false;   //表示拦截....
    }
}

3.8.ThreadLocal介绍

名词解释: 本地线程变量

3.8.1 工作原理

作用: 在线程内部(一个线程)实现数据的共享.
在这里插入图片描述

3.8.2 ThreadLocal工具API编辑

package com.jt.util;

import com.jt.pojo.User;

public class UserThreadLocal {

    private static ThreadLocal<User> threadLocal = new ThreadLocal<>();

    public static void setUser(User user){

        threadLocal.set(user);
    }

    public static User getUser(){

        return threadLocal.get();
    }

    public static void remove(){

        threadLocal.remove();
    }
}

3.8.3 重构拦截器

package com.jt.interceptor;

import com.jt.pojo.User;
import com.jt.util.CookieUtil;
import com.jt.util.ObjectMapperUtil;
import com.jt.util.UserThreadLocal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import redis.clients.jedis.JedisCluster;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component  //将拦截器交给spring容器管理
public class UserInterceptor implements HandlerInterceptor {

    private static final String JT_TICKET="JT_TICKET";

    @Autowired
    private JedisCluster jedisCluster;

    /**
     * 返回值说明:
     *      1.false  表示拦截  一般都要配合重定向的方式使用.
     *      2.true   表示放行
     *
     * 如何实现业务:
     *      判断用户是否登录:   Cookie数据  检查redis中的数据.
     *      重定向到系统登录页面.
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //1.校验Cookie中是否有结果
        Cookie cookie = CookieUtil.getCookie(request, JT_TICKET);

        //2.校验Cookie是否有效
        if(cookie != null){
            String ticket = cookie.getValue();
            if(StringUtils.hasLength(ticket)){
                //执行后续任务  校验redis中是否有结果
                if(jedisCluster.exists(ticket)){
                    String json = jedisCluster.get(ticket);
                    User user = ObjectMapperUtil.toObject(json,User.class);
                    //利用Request对象将数据进行传递  最为常见的参数传递的方式
                    request.setAttribute("JT_USER", user);

                    //ThreadLocal机制
                    UserThreadLocal.setUser(user);

                    //表示用户登录过  直接返回true
                    return true;
                }
            }
            //没有结果,则cookie数据有误,应该删除
            CookieUtil.addCookie(response, JT_TICKET, "", "/", "jt.com", 0);
        }

        //3.如果数据为空,则重定向到系统首页
        response.sendRedirect("/user/login.html");
        return false;   //表示拦截....
    }


    //为了防止内存泄露,将多余的数据删除
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        //移除request对象
        request.removeAttribute("JT_USER");
        //移除threadLocal数据
        UserThreadLocal.remove();
    }
}

3.8.4 编辑CartController

在这里插入图片描述

3.8.5 关于ThreadLocal线程说明

思考题: JT-WEB中ThreadLocal.set(xxx),问 在jt-cart中的service能否执行ThreadLocal.get()???
A. 不能
在这里插入图片描述

4.商品订单的实现

4.1 订单确认页面跳转

4.1.1 需求分析

页面跳转: order-cart.jsp页面,需要展现商品数据信息,同时有收件人地址信息.
在这里插入图片描述

4.1.2 编辑OrderController

完成订单确认页面跳转

package com.jt.controller;

import com.alibaba.dubbo.config.annotation.Reference;
import com.jt.pojo.Cart;
import com.jt.service.DubboCartService;
import com.jt.util.UserThreadLocal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.List;

@Controller
@RequestMapping("/order")
public class OrderController {

    @Reference(check = false)
    private DubboCartService cartService;

    /**
     * 1.实现订单确认页面跳转
     * url地址: http://www.jt.com/order/create.html
     * 参数说明:  获取userId
     * 返回值结果: 订单确认页面  order-cart.jsp
     * 页面取值方式:  ${carts}
     */
    @RequestMapping("/create")
    public String orderCart(Model model){
        long userId = UserThreadLocal.getUser().getId();
        List<Cart> cartList = cartService.findCartList(userId);
        model.addAttribute("carts", cartList);
        return "order-cart";
    }


}


在这里插入图片描述

4.2 创建订单项目

4.2.1 订单模块表设计

在这里插入图片描述

4.2.2 导入POJO对象

在这里插入图片描述

4.2.3 创建订单项目

1).创建项目
在这里插入图片描述
2).添加继承/依赖/插件

<parent>
        <artifactId>jt</artifactId>
        <groupId>com.jt</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>


    <!--添加jar包文件依赖-->
    <dependencies>
        <dependency>
            <groupId>com.jt</groupId>
            <artifactId>jt-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <!--所有业务系统,必须添加build标签-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>


3).完成订单模块创建
在这里插入图片描述

4.3 SpringMVC 参数传递说明

4.3.1 简单参数赋值

1).html标记

<input    type="text" name="name"  value="二郎神"/>
<input    type="text" name="age"     value="18"/>

2).controller方法
在这里插入图片描述

4.3.2 对象赋值

1).html标记

<input    type="text" name="name"  value="二郎神"/>
<input    type="text" name="age"     value="18"/>

2).利用对象的方式接收参数
在这里插入图片描述

4.3.3 对象的引用赋值

问题: 如果页面中有重名属性,如何处理???
解决方案: 利用对象的引用封装

1).html标记

<input    type="text" name="name"  value="二郎神"/>  
<input    type="text" name="age"     value="18"/>
<input    type="text" name="dog.name"  value="哮天犬"/>
<input    type="text" name="dog.age"     value="15"/>
<input    type="text" name="hobbys[0]"     value="敲代码"/>
<input    type="text" name="hobbys[1]"     value="学JAVA"/>

2).参数的获取
在这里插入图片描述

4.4 订单业务实现

4.4.1 业务分析

1). url分析
在这里插入图片描述
2).页面参数分析
在这里插入图片描述
3).页面结构分析
在这里插入图片描述
4).POJO对象赋值
在这里插入图片描述
5).页面JS分析
在这里插入图片描述

4.4.2 编辑OrderController

在这里插入图片描述

4.4.3 编辑OrderService

package com.jt.service;

import java.util.Calendar;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.jt.mapper.OrderItemMapper;
import com.jt.mapper.OrderMapper;
import com.jt.mapper.OrderShippingMapper;
import com.jt.pojo.Order;
import com.jt.pojo.OrderItem;
import com.jt.pojo.OrderShipping;

@Service
public class OrderServiceImpl implements DubboOrderService {
	
	@Autowired
	private OrderMapper orderMapper;
	@Autowired
	private OrderShippingMapper orderShippingMapper;
	@Autowired
	private OrderItemMapper orderItemMapper;


	@Override
	public String saveOrder(Order order) {
		//字符串拼接
		String orderId =  "" + order.getUserId() + System.currentTimeMillis();
		//1.完成订单入库操作
		order.setOrderId(orderId).setStatus(1);	//未付款状态
		orderMapper.insert(order);
		//2.入库订单物流信息
		OrderShipping orderShipping = order.getOrderShipping();
		orderShipping.setOrderId(orderId);
		orderShippingMapper.insert(orderShipping);
		//3.完成订单商品入库操作
		List<OrderItem> orderItems = order.getOrderItems();
		for(OrderItem orderItem : orderItems){
			orderItem.setOrderId(orderId);
			orderItemMapper.insert(orderItem);
		}
		System.out.println("订单入库完成!!!!");
		return orderId;
	}
}

4.5 订单查询

4.5.1 页面分析

在这里插入图片描述

4.5.2 编辑OrderController

在这里插入图片描述

4.5.3 编辑OrderService

在这里插入图片描述

4.5.4 页面效果展现

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_36844475/article/details/111394509
SOA