目录
Easymall项目分布式拆分整合(七)
一.Easymall分布式项目结构
二.用户搭建(最基础的六部)
1.创建一个quickstart的maven工程(src/main/resources)
2.pom继承parent,依赖common
3.后台user系统需要的其他依赖
4.application.properties文件
5.启动类(MapperScan)
6.nginx和hosts文件
1.nginx配置
2.hoste文件配置
三.用户系统的功能
一.注册用户用户名校验
1.接口文件
2.UserController
3.UserService
二.注册表单数据的提交
1.接口文件
2.UserController
3.UserService
三.实现注册方法与前台系统的整合
1.调用结构
2.前台的结构搭建
3.导入一个UserController类
3.创建一个UserService等待逻辑编写
1.用户名称校验
2.打开controller对应的交互逻辑代码注册user
四.用户的登录逻辑
一.接口方法,处理登录的校验
1.登录的用户系统校验逻辑
2.接口文件
3.编写用户登录逻辑
1.UserController类
2.RedisCumUtils中添加一个超时方法
3.UserService(redisUtil)类
1.接口文件
2.UserController
3.UserService
cn..tedu
springboot-common-easymall
0.0.1-SNAPSHOT
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
junit
junit
3.8.1
test
server.port=8093
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql:///easydb?useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
spring.datasource.password=root
spring.datasource.username=root
mybatis.configuration.mapUnderscoreToCamelCase=true
mybatis.mapperLocations=classpath:mapper/*.xml
mybatis.typeAliasesPackage=com.jt.common.pojo
redis.nodes=10.42.60.249:6379
redis.maxTotal=200
redis.maxIdle=8
redis.minIdle=3
package com.jt;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.jt.user.mapper")
public class StarterUser {
public static void main(String[] args) {
SpringApplication.run(StarterUser.class, args);
}
}
#User服务器
server {
listen 80;
server_name user.easymall.com;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
location / {
proxy_pass http://127.0.0.1:8093;
proxy_connect_timeout 600;
proxy_read_timeout 600;
}
}
127.0.0.1 |
user.easymall.com |
请求地址 |
user.easymall.com/user/checkUserName/{userName} |
请求方式 |
GET |
请求参数 |
路径传参的String userName |
返回数据 |
存在返回1不可用,不存在返回0表示可用 |
public class UserController {
@Autowired
private UserService userService;
//接收前台的请求,返回数据库用户名可用还是不可用
@RequestMapping("checkUserName/{userName}")
public Integer checkUserName(@PathVariable String userName){
Integer exist=userService.checkUserName(userName);
return exist;
}
@Autowired
private UserMapper userMapper;
public Integer checkUserName(String userName) {
return userMapper.queryName(userName);
}
请求地址 |
user.easymall.com/user/save |
请求方式 |
post |
请求参数 |
User user对象接收,缺少的属性type,默认0,userId使用UUID解决 |
返回数据 |
1.SysResult的结构的数据,需要前端调用之后解析数据,可以满足返回数据的丰富性(既可以传递结果,也可以传递消息) 2.新增成功失败返回1/0 |
@RequestMapping("save")
public Integer saveUser(User user){
try{
userService.saveUser(user);
return 1;
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
public void saveUser(User user) {
//user的id,type,password的加密
user.setUserId(UUID.randomUUID().toString());
user.setUserPassword(MD5Util.md5(user.getUserPassword()));
user.setUserType(0);
userMapper.insertUser(user);
}
将easymall单体项目中的UserController(包含了与页面的交互逻辑),粘贴到web前端系统
@Controller
public class UserController {
@Autowired
private UserService userService;
//ajax查询用户是否名称存在
@RequestMapping(value="user_ajax/checkUserName"
,method=RequestMethod.POST)
@ResponseBody
public SysResult checkUserName(String userName){
int exist=userService.queryName(userName);
//数据库如果存在,返回1,数据库如果不存在返回0
return SysResult.build(exist, "ok", null);
}
@RequestMapping(value="/user_ajax/regist"
,method=RequestMethod.POST)
@ResponseBody
public SysResult saveUser(User user){
try{
//业务层调用,插入表格数据
userService.saveUser(user);
return SysResult.build(1, null, null);
}catch(Exception e){
e.printStackTrace();
return SysResult.build(0, null, null);
}
}
private static final String url="http://user.easymall.com/user/";
//注入httpClient
@Autowired
private HttpClientService client;
public int queryName(String userName) {
//按照接口文件进行调用和传参和数据的接收
String userUrl=url+"checkUserName/"+userName;
try{
String exist=client.doGet(userUrl);
return Integer.parseInt(exist);
}catch(Exception e){
e.printStackTrace();
return 0;
}
}
编写service中saveUser方法
public void saveUser(User user) {
//按照注册接口调用user系统
String userUrl=url+"save";
try{
//生成参数
Map param=new HashMap();
param.put("userName", user.getUserName());
param.put("userPassword", user.getUserPassword());
param.put("userEmail", user.getUserEmail());
param.put("userNickname", user.getUserNickname());
client.doPost(userUrl,param);
}catch(Exception e){
e.printStackTrace();
}
}
用户登录逻辑,需要处理session共享问题,将用户信息,存储在redis中将key作为数据返回页面时,放到cookie中,只要cookie中key,后续访问逻辑www.easymall.com系统时,都会携带这个key,从而可以处理获取redis的数据使用.
请求地址 |
user.easymall.com/user/login |
请求的参数 |
User user对象接收,自动封装了userName和Password |
请求方式 |
get/post |
返回数据 |
将存储在redis中的当前ticket的key值返回,存储到redis中的数据表示一个用户的登录状态(userJson),所以不能是永久数据,设置超时(做后续的逻辑,同一个用户最多登录一次) |
//验证登录的用户名密码是否正确
@RequestMapping("login")
public String doLogin(User user){
String ticket=userService.doLogin(user);
//成功登录返回redis的key,失败返回""
return ticket;
}
//封装一个带有超时逻辑的add方法
public void addOrUpdateExpire(String key,String value,Integer seconds){
ShardedJedis jedis = pool.getResource();
try{
jedis.setex(key, seconds, value);
}catch(Exception e){
//异常处理逻辑
}finally{
pool.returnBrokenResource(jedis);
}
}
@Autowired
private RedisCumUtils redis;
public String doLogin(User user) {
//查询一下数据库数据,是否存在userExist
//处理用户密码加密
user.setUserPassword(MD5Util.md5(user.getUserPassword()));
User exist=userMapper.selectExist(user);
try{
if(exist==null){//登录失败
return "";
}else{//表示成功,存储在redis返回key值
String ticket=MD5Util.md5("EM_TICKET"+System.currentTimeMillis()
+exist.getUserId());
//准备value值,mapper转化user为json字符串
String userJson=MapperUtils.MP.writeValueAsString(exist);
//set数据到redis供后续逻辑使用
redis.addOrUpdateExpire(ticket, userJson, 60*30);
//验证最多一个用户登录,顶替登录逻辑
//TODO
return ticket;
}
}catch(Exception e){
e.printStackTrace();
return "";
}
}
将jsp文件中head.jsp的js代码修改访问的域名,从原有的sso.jt.com换成user.jt.com
请求地址 |
user.easymall.com/user/query/{ticket} |
请求方式 |
get |
请求参数 |
redis中的key值,ticket路径接参 String callback |
返回数据 |
通过对callback的判断,实现返回数据的封装, if(callback==null)说明不是jsonp请求,返回syResult的json字符串 if(callback!=null)说明是jsonp请求,返回 callback(+sysResultJson+) sysResult的status==200表示成功,201表示失败 |
//校验登录状态,查询redis数据
@RequestMapping("query/{ticket}")
public String checkTicket(@PathVariable String ticket
,String callback){
try{
//走到redis校验数据
String userJson=userService.queryTicket(ticket);
//封装返回的json数据,SysResult
SysResult result=null;
if(StringUtils.isNotEmpty(userJson)){//登录状态正常
result=SysResult.build(200, "", userJson);
}else{
result=SysResult.build(201, "", null);
}
//将result解析成json等待返回使用
String resultJson=MapperUtils.MP.writeValueAsString(result);
//判断请求需要的数据格式,callback
if(callback==null){
return resultJson;//作为json字符串返回
}else{
return callback+"("+resultJson+")";//jsonp格式返回
}
}catch(Exception e){
return "";
}
}
public String queryTicket(String ticket) {
//TODO 超时时间延长--续租
return redis.query(ticket);
}