1. 实现用户单点登录
1.1 用户登录
1.1.1 单点登录实现策略
需求: 用户只登录一次,就可以实现免密登录30天,并且项目子系统也可以实现免密登录
单点登录实现步骤:
- 用户输入用户名和密码点击登录 发送到JT-WEB服务器
- JT-WEB服务器将数据发送到JT-SSO完成数据校验
- JT-SSO 校验通过之后,保存到redis中 以TICKET-JSON 注意超时时间
- 当数据保存到redis中之后,将数据TICKET数据返回.
- 利用Cookie工具将数据保存
- 注意将Cookie设置为共享数据…
1.1.2 页面JS分析
1.1.3 编辑UserController
@ResponseBody
@RequestMapping("/doLogin")
public SysResult doLogin(User user, HttpServletResponse response){
//1.判断数据是否有效
if(StringUtils.isEmpty(user.getUsername()) || StringUtils.isEmpty(user.getPassword())){
return SysResult.fail();
}
//2.完成用户信息校验
String ticket = dubboUserService.findUserByUp(user);
//3.判断返回值是否有效
if(StringUtils.hasLength(ticket)){
//开始进行单点登录操作
Cookie cookie = new Cookie("JT_TICKET",ticket);
cookie.setMaxAge(30*24*60*60); //30天超时
cookie.setPath("/"); //设定cookie访问路径
cookie.setDomain("jt.com"); //设定数据共享
response.addCookie(cookie); //上传Cookie
return SysResult.sucess(); //登录成功之后返回
}
return SysResult.fail();
}
1.1.4 编辑DubboUserService
package com.jt.service;
import com.alibaba.dubbo.config.annotation.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.jt.Util.ObjectMapperUtil;
import com.jt.mapper.UserMapper;
import com.jt.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import redis.clients.jedis.JedisCluster;
import java.util.List;
import java.util.UUID;
@Service(timeout = 3000)
public class DubboUserServiceImpl implements DubboUserService{
@Autowired
private UserMapper userMapper;
@Autowired
private JedisCluster jedisCluster;
@Override
public void insert(User user) {
user.setEmail(user.getPhone());
//实现密码加密
String md5Password = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
user.setPassword(md5Password);
userMapper.insert(user);
}
@Override
public String findUserByUp(User user) {
//1.密码加密
String md5Pass = DigestUtils.md5DigestAsHex(user.getPassword().getBytes());
//a66abb5684c45962d887564f08346e8d
user.setPassword(md5Pass);
//2.根据用户名和密码 查询数据 根据对象中不为null的属性当做where条件
QueryWrapper<User> queryWrapper = new QueryWrapper<>(user);
User userDB = userMapper.selectOne(queryWrapper);
//3.判断用户信息是否有效
if(userDB == null){
//如果查询结果为null,则表示用户名或密码错误
return null;
}
//4.如果用户名和密码正确则开始单点登录操作
String ticket = UUID.randomUUID().toString().replace("-", "");
//5.需要将用户数据转户为JSON 需要将数据进行脱敏处理
userDB.setPassword("123456你试试!!!"); //假数据
String json = ObjectMapperUtil.toJson(userDB);
//6.将数据保存到redis中 30天自动失效
int seconds = 30 * 24 * 60 * 60;
jedisCluster.setex(ticket, seconds, json);
return ticket;
}
}
1.1.5 登录测试
2. 实现用户信息回显功能
2.1 业务说明
使用跨域方式,实现数据获取
2.2 JS分析
2.3 编辑JT-SSO UserController
/**
* url: http://sso.jt.com/user/query/sxxx
* 参数: ticket信息
* 返回值结果: callback(Sysresult对象)
*/
@RequestMapping("query/{ticket}")
public JSONPObject findUserByTicket(@PathVariable String ticket,String callback){
String json = jedisCluster.get(ticket);
if(StringUtils.hasLength(json)){
return new JSONPObject(callback, SysResult.sucess(json));
}else {
//缓存中没有数据
return new JSONPObject(callback, SysResult.fail());
}
}
2.4 页面呈现
3. 实现退出操作
3.1 业务需求分析
- 当用户点击退出按钮时,应该重定向到系统的首页. redirect:/xxxxxxx
- 删除Cookie中的数据
- 删除Redis中的数据
3.1 页面url分析
3.2 编辑cookie工具类
package com.jt.Util;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class CookieUtils {
/**
* 1.保存cookie
*/
public static void addCookie(HttpServletResponse response, String cookieName, String cookieValue, String domain, int seconds){
Cookie cookie = new Cookie(cookieName,cookieValue);
cookie.setDomain(domain);
cookie.setMaxAge(seconds);
cookie.setPath("/");
response.addCookie(cookie);
}
/**
* 2. 获取cookie
*/
public static Cookie getCookie(HttpServletRequest request,String cookieName){
Cookie cookieTemp = null;
Cookie[] cookies = request.getCookies();
if(cookies != null && cookies.length > 0){
for(Cookie cookie:cookies){
if(cookieName.equals(cookie.getName())){
cookieTemp = cookie;
break;
}
}
}
return cookieTemp;
}
/**
* 获取cookie的value
*/
public static String getCookieValue(HttpServletRequest request,String cookieName){
Cookie cookie = getCookie(request, cookieName);
return cookie==null?null:cookie.getValue();
}
}
3.3 编辑jt-web UserController
/**
* 用户退出操作
* url : http://www.jt.com/user/logout.html
* 返回值: 重定向到系统首页
* 实现步骤:
* 1.从cookie中获取数据
* 2.删除redis中的记录
* 3.删除cookie中的记录
*/
@RequestMapping("/logout")
private String doLogOut(HttpServletRequest request,HttpServletResponse response){
//1.从cookie中获取数据
String ticket = CookieUtils.getCookieValue(request, "JT_TICKET");
if(StringUtils.hasLength(ticket)){
//删除redis中的数据
jedis.del(ticket);
//设置毫秒值为0则直接删除
CookieUtils.addCookie(response,"JT_TICKET","", "jt.com", 0);
}
//跳转系统首页
return "redirect:/";
}
4. 实现购物车模块操作
4.1 编辑POJO类
package com.jt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
@TableName("tb_cart")
@Data
@Accessors(chain = true)
public class Cart extends BasePojo{
@TableId(type= IdType.AUTO)
private Long id;//id属性
private Long userId;//用户编号
private Long itemId;//商品编号
private String itemTitle;//商品标题
private String itemImage;//商品图片
private Long itemPrice;//商品价格
private Integer num;//商品数量
}
4.2 创建jt-cart工程
4.2.1 配置yml文件
server:
port: 8094
servlet:
context-path: /
spring:
datasource:
# driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/jtdb?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: root
#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 #每一个服务都有自己特定的端口 不能重复.
4.2.2 创建jt-cart DubboCartServiceImpl
4.3 购物车列表页面展现
4.3.1 页面url分析
4.3.2 编辑CartController
@Controller
@RequestMapping("/cart")
public class CartController {
@Reference(check = false)
private DubboCartService cartService;
/**
* url: http://www.jt.com/cart/show.html
* 返回值: 购物车列表页面 cart.jsp
* 页面数据取值: ${cartList}
*/
@RequestMapping("/show")
public String cartShow(Model model){
//1.获取用户信息 ticket redis userJSON user对象 userId
long userId = 7L;
List<Cart> cartList = cartService.findCartListByUserId(userId);
model.addAttribute("cartList",cartList);
return "cart";
}
}
4.3.3 编辑CartService
@Service(timeout = 3000)
public class DubboCartServiceImpl implements DubboCartService{
@Autowired
private CartMapper cartMapper;
@Override
public List<Cart> findCartListByUserId(long userId) {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("user_id", userId);
return cartMapper.selectList(queryWrapper);
}
}
4.4 实现购物车数量更新
4.4.1 4.4.1 页面url分析
4.4.2 页面JS分析(cart-js)
- 页面标识
- 编辑页面JS
4.4.3 编辑jt-web CartController
/**
* 实现商品数量的更新操作
* url: http://www.jt.com/cart/update/num/xxxxx/16
* 参数: itemId/num
* 返回值: void
*
*/
@RequestMapping("/update/{itemId}/{num}")
@ResponseBody
public void updateNum(Cart cart){
long userId = 7L;
cart.setUserId(userId);
cartService.updateNum(cart);
}
4.4.4 编辑jt-cart DubboCartServiceImpl
@Override
public void updateNum(Cart cart) {
/*
sql: update tb_cart set num=#{num},updated=#{updated} where item_id=#{itemId} and user_id=#{userId}
*/
Cart cartTemp = new Cart();
cartTemp.setNum(cart.getNum());
QueryWrapper<Cart> updateWrapper = new QueryWrapper<>();
updateWrapper.eq("user_id", cart.getUserId());
updateWrapper.eq("item_id", cart.getItemId());
cartMapper.update(cartTemp, updateWrapper);
}
4.5 购物车入库操作
- 当用户点击加入购物车时,可以将数据添加到购物车列表中
- 如果点击添加购物车按钮,跳转到购物车列表页面中
- 页面点击按钮编辑
<a class="btn-append " id="InitCartUrl" onclick="addCart();" clstag="shangpin|keycount|product|initcarturl">加入购物车<b></b></a>
- 页面JS点击函数
//利用post传值
function addCart(){
var url = "http://www.jt.com/cart/add/${item.id}.html";
document.forms[0].action = url; //js设置提交链接
document.forms[0].submit(); //js表单提交
}
- 页面HTML标签
<form id="cartForm" method="post">
<input class="text" id="buy-num" name="num" value="1" onkeyup="setAmount.modify('#buy-num');"/>
<input type="hidden" class="text" name="itemTitle" value="${item.title }"/>
<input type="hidden" class="text" name="itemImage" value="${item.images[0]}"/>
<input type="hidden" class="text" name="itemPrice" value="${item.price}"/>
</form>
4.5.1 编辑CartController
/**
* 业务逻辑:
* 如果购物车中已经存在数据 则更新数量.
* 如果购物车中没有数据 则新增数据.
*
* 更新数量:
* update tb_cart set num=#{num} where id = #{id}
* @param cart
*/
@Override
public void addCart(Cart cart) {
//1. 查询数据库 校验是否有值 user_id,item_id
QueryWrapper<Cart> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", cart.getUserId());
queryWrapper.eq("user_id", cart.getItemId());
Cart cartDB = cartMapper.selectOne(queryWrapper);
if(cartDB==null){
cartMapper.insert(cart);
}else{
//更新数据库数量
int num = cart.getNum() + cartDB.getNum();
Cart cartTemp = new Cart();
cartTemp.setId(cartDB.getId());
cartTemp.setNum(num);
cartMapper.updateById(cartTemp);
}
}