Easymall項目分佈式拆分整合(七)

                            Easymall項目分佈式拆分整合(七)


一.Easymall分佈式項目結構

二.用戶搭建(最基礎的六部)

1.創建一個quickstart的maven工程(src/main/resources)

2.pom繼承parent,依賴common

3.後臺user系統需要的其他依賴

  <dependencies>
  <dependency>
  	<groupId>cn..tedu</groupId>
  	<artifactId>springboot-common-easymall</artifactId>
  	<version>0.0.1-SNAPSHOT</version>
  </dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-jdbc</artifactId>
  	</dependency>
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  	</dependency>
  	<dependency>
  		<groupId>org.mybatis.spring.boot</groupId>
       	<artifactId>mybatis-spring-boot-starter</artifactId>	
  	</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

4.application.properties文件

  • 端口8093
  • datasource
  • mybatis
  • redis
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

 

5.啓動類(MapperScan)

  • 掃描接口mapper的包
  • UserMapper(重新導入User的包名,common)
  • UserMapper.xml(修改namespce對應新的接口全路徑)
  • 啓動類
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);
	}
}

6.nginx和hosts文件

1.nginx配置

	#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;
		}
	}

2.hoste文件配置

127.0.0.1

user.easymall.com

三.用戶系統的功能

.註冊用戶用戶名校驗

1.接口文件

請求地址

user.easymall.com/user/checkUserName/{userName}

請求方式

GET

請求參數

路徑傳參的String userName

返回數據

存在返回1不可用,不存在返回0表示可用

2.UserController

public class UserController {
	@Autowired
	private UserService userService;
	//接收前臺的請求,返回數據庫用戶名可用還是不可用
	@RequestMapping("checkUserName/{userName}")
	public Integer checkUserName(@PathVariable String userName){
		Integer exist=userService.checkUserName(userName);
		return exist;
	}

3.UserService

	@Autowired
	private UserMapper userMapper;
	public Integer checkUserName(String userName) {
		return userMapper.queryName(userName);
	}

 

二.註冊表單數據的提交

1.接口文件

請求地址

user.easymall.com/user/save

請求方式

post

請求參數

User user對象接收,缺少的屬性type,默認0,userId使用UUID解決

返回數據

1.SysResult的結構的數據,需要前端調用之後解析數據,可以滿足返回數據的豐富性(既可以傳遞結果,也可以傳遞消息)

2.新增成功失敗返回1/0

2.UserController

	@RequestMapping("save")
	public Integer saveUser(User user){
		try{
			userService.saveUser(user);
			return 1;
		}catch(Exception e){
			e.printStackTrace();
			return 0;
		}
	}

3.UserService

	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);
	}

 

三.實現註冊方法與前臺系統的整合

1.調用結構

2.前臺的結構搭建

將easymall單體項目中的UserController(包含了與頁面的交互邏輯),粘貼到web前端系統

3.導入一個UserController類

@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);
		}
	}
	

3.創建一個UserService等待邏輯編寫

1.用戶名稱校驗

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;
		}
	}

2.打開controller對應的交互邏輯代碼註冊user

編寫service中saveUser方法 

   public void saveUser(User user) {
        //按照註冊接口調用user系統
        String userUrl=url+"save";
        try{
            //生成參數
            Map<String,Object> param=new HashMap<String,Object>();
            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的數據使用.

一.接口方法,處理登錄的校驗

1.登錄的用戶系統校驗邏輯

  • 用戶名密碼的校驗(where userName password是否存在數據)
  • 如果不存在,按照接口返回不存在的數據
  • 如果存在,將查詢到的user作爲整體數據存放到redis key值計算邏輯(公式:"EM_TICKET"+currentTime+userId),value值就是userJson字符串
  • 將ticket的key值返回給前臺

2.接口文件

請求地址

user.easymall.com/user/login

請求的參數

User user對象接收,自動封裝了userName和Password

請求方式

get/post

返回數據

將存儲在redis中的當前ticket的key值返回,存儲到redis中的數據表示一個用戶的登錄狀態(userJson),所以不能是永久數據,設置超時(做後續的邏輯,同一個用戶最多登錄一次)

 

3.編寫用戶登錄邏輯

1.UserController類

//驗證登錄的用戶名密碼是否正確
	@RequestMapping("login")
	public String doLogin(User user){
		String ticket=userService.doLogin(user);
		//成功登錄返回redis的key,失敗返回""
		return ticket;
	}

2.RedisCumUtils中添加一個超時方法

	//封裝一個帶有超時邏輯的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);
			}
		}

3.UserService(redisUtil)類

@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 "";
		}
	}

4.js頁面發起ajax請求獲取user登錄的狀態信息(攜帶cookie的值)

將jsp文件中head.jsp的js代碼修改訪問的域名,從原有的sso.jt.com換成user.jt.com

1.接口文件

請求地址

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表示失敗

2.UserController

//校驗登錄狀態,查詢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 "";
		}	
	}

3.UserService

	public String queryTicket(String ticket) {
		//TODO 超時時間延長--續租
		
		return redis.query(ticket);
	}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章