SSM项目第3讲

web后端开始做登录

web后端微信登录,其中用到了redis

小补充:如果说端口中之跑一个项目可以不加虚拟路径右击工程设置中web project setting

先确定微信用户类内容

package com.system.entity.pojo;

public class WxUser {
	private  String  userId;
	private  String  nickname;
	private  String  openid;
	private  String  gender;
	private  String  city;
	private  String  province;
	private  String  country;
	private  String  avatarurl;
    
    ....getset自己添加
}

加入相关架包

  1. 首先在lib里面加架包

    bcprov-jdk16-1.46.jar    		传输加密解密类
    httpclient-4.5.6jar			
    httpcore-4.4.10.jar
    httpmime-4.5.6.jar				HTTP传输类
    jedis-2.9.0.jar					redis类   
    

2.可知下面的工作分为三大部分:

  • 微信小程序登录
    • 设置HTTP传输
    • 设置redis数据库
    • 设置WeChat传输

设置HTTP传输

HTTP传输反馈类

  1. 在com.entity.vo下新建传输回馈实例类,ResultVo.java

HTTP工具类

  1. 在com.common.util下新建传输连接工具类,HttpUtil.java

HTTP处理工具类

  1. 在com.common.util下新建传输处理连接成为接口工具类,HttpUtil.java

设置redis数据库

1.在com->conf里面新建spring-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="  
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<!-- 最大连接数 -->
		<property name="maxTotal" value="30" />
		<!-- 最大空闲连接数 -->
		<property name="maxIdle" value="10" />
		<!-- 每次释放连接的最大数目 -->
		<property name="numTestsPerEvictionRun" value="1024" />
		<!-- 释放连接的扫描间隔(毫秒) -->
		<property name="timeBetweenEvictionRunsMillis" value="30000" />
		<!-- 连接最小空闲时间 -->
		<property name="minEvictableIdleTimeMillis" value="1800000" />
		<!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
		<property name="softMinEvictableIdleTimeMillis" value="10000" />
		<!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
		<property name="maxWaitMillis" value="1500" />
		<!-- 在获取连接的时候检查有效性, 默认false -->
		<property name="testOnBorrow" value="true" />
		<!-- 在空闲时检查有效性, 默认false -->
		<property name="testWhileIdle" value="true" />
		<!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
		<property name="blockWhenExhausted" value="false" />
	</bean>	
	

	<bean id="redisClient" class="redis.clients.jedis.JedisPool">
					<constructor-arg name="host" value="xxx.xxx.xxx.xxx"/>
					<constructor-arg name="port" value="6379"/>
					<constructor-arg name="poolConfig" ref="jedisPoolConfig"/>
					<constructor-arg name="timeout" value="10000"/>
					
	</bean>
</beans>

代码解析

<constructor-arg name="host" value="xxx.xxx.xxx.xxx"/>
<constructor-arg name="port" value="6379"/>
    ......

这里填写自己redis的地址和端口,一般默认端口6379

2.spring.xml引入redis

<!-- 引入redis -->
<import resource="spring-redis.xml"/>
		

3.lib或者maven中引入redis架包

   <dependency>
               <groupId>redis.clients</groupId>
               <artifactId>jedis</artifactId>
               <version>2.9.0</version>
           </dependency>
      <dependency>
       <groupId>org.bouncycastle</groupId>
       <artifactId>bcprov-jdk16</artifactId>
       <version>1.46</version>
   </dependency>

4.编写redis服务端

      package com.system.service.impl;
      
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      
      import com.system.service.JedisClientService;
      
      import redis.clients.jedis.Jedis;
      import redis.clients.jedis.JedisPool;
      
      @Service
      public class JedisClientServiceImpl implements  JedisClientService{
      
      	@Autowired
      	private JedisPool redisClient;
      	
      
      	public Long del(String key) {
      		Jedis jedis=null;
      		 jedis =getJedis(); 
      		 Long del=null;
      		 try {
      		 del = jedis.del(key);
      		} catch (Exception e) {
      			returnResource(jedis);
                  e.printStackTrace(); 
                  throw new RuntimeException("操作redis出错");
      		}
      		 finally{
      	    	   returnResource(jedis);
      	       }
      		return del;
      	} 
      	/**
      	 * 通过键得到值
      	 */
      	public String get(String key) {
      		
      		Jedis jedis =getJedis();
      		String value=jedis.get(key);
      		returnResource(jedis);
      		return value;
      		
      		
      	}
      	public String set(String key, String value) {
      		Jedis jedis =getJedis();
      		String string=null;
      		try {
      			string=jedis.set(key,value);
      		} catch (Exception e) {
      			returnResource(jedis);
                  e.printStackTrace(); 
                  throw new RuntimeException("操作redis出错");
      		}
      		System.out.println(string);
      		returnResource(jedis);
      		return "";
      	}
      	public void returnResource(Jedis jedis) {  
              if (null != jedis) {  
              	redisClient.returnResourceObject(jedis);  
              }  
          }  
      	private Jedis getJedis() {  
              Jedis jedis =redisClient.getResource();
              int i=0;
              while (i<=20) {
                  if (null != jedis){
                      break;  
                  } else {
                      jedis = redisClient.getResource();
                  }
                  i++;
                 if(i==20)
                throw new RuntimeException("获取连接失败,此订单未保存");
              }  
              return jedis;
      	}
      
      }
      
package com.system.service;

public interface JedisClientService {

	String get(String openId);

	Long del(String oldSeesionKey);

	String set(String rsession, String string);

}

设置WeChat传输

1.自底层向上先写mapper中的xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.system.mapper.WxUserMapper">



  <select id="selectByOpenId" parameterType="com.system.entity.pojo.WxUser" resultType="com.system.entity.pojo.WxUser">
   select cu.user_id as  userId,cu.*, cu.user_id as  userId from wx_user cu where cu.openid=#{openid} 
  </select>


<insert id="insertSelective"   parameterType="com.system.entity.pojo.WxUser">
		insert into wx_user
		(user_id,nickname,openid,gender,city,province,country,avatarurl)
		values
		(#{userId},#{nickname},#{openid},#{gender},#{city},#{province},#{country},#{avatarurl});
	</insert>
	
	
	<update id="updateByPrimaryKeySelective" parameterType="com.system.entity.pojo.WxUser" >
		update course set
		nickname=#{nickname},gender=#{gender},city=#{city},province=#{province},country=#{country},avatarurl=#{avatarurl}
		where
		user_id=#{userId}	
	</update>
	
</mapper>

2.然后是接口

package com.system.mapper;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Param;

import com.system.entity.pojo.Course;
import com.system.entity.pojo.WxUser;


/**
 *
 */
public interface WxUserMapper {

	WxUser selectByOpenId(WxUser wxUser);

	void insertSelective(WxUser igWuser);

	void updateByPrimaryKeySelective(WxUser igWuser);
	
	

}

3.写server层和接口

   package com.system.service.impl;
   
   import java.util.HashMap;
   import java.util.Map;
   import java.util.UUID;
   
   import org.apache.commons.lang3.StringUtils;
   import org.springframework.beans.factory.annotation.Autowired;
   import org.springframework.stereotype.Service;
   
   import com.alibaba.fastjson.JSON;
   import com.alibaba.fastjson.JSONObject;
   import com.system.commom.constan.Constant;
   import com.system.commom.util.AesCbcUtil;
   import com.system.commom.util.HttpUtil;
   import com.system.commom.util.ResultUtil;
   import com.system.entity.pojo.WxUser;
   import com.system.entity.vo.ResultVo;
   import com.system.mapper.WxUserMapper;
   import com.system.service.AppLoginService;
   import com.system.service.JedisClientService;
   
   
   @Service
   public class AppLoginServiceImpl implements AppLoginService{
   	
   	@Autowired
   	private WxUserMapper wxUserMapper;
   	
   	@Autowired
   	private JedisClientService igJedisClientService;
   
   	public ResultVo loginByWeixin(String encryptedData, String iv, String code) {
   		
           String url = "https://api.weixin.qq.com/sns/jscode2session";
           Map<String,Object> map=new HashMap<String,Object>();
           map.put("appid", Constant.APP_ID );
           map.put("secret", Constant.APP_SECRET);
           map.put("js_code", code);
           map.put("grant_type", "authorization_code");
           String ret = HttpUtil.doPostSSL(url, map);
           if(StringUtils.isEmpty(ret)){
           	 return ResultUtil.fail("网络超时");
           }else{
           	WxUser igWuser=null;
           	  
   	          JSONObject obj = JSON.parseObject(ret);
   	          System.out.println(obj.toString());
   	          if (obj.containsKey("errcode")) {
   	            String errcode = obj.get("errcode").toString();
   	            return ResultUtil.fail("微信返回的错误吗是"+errcode);
   	          } else if (obj.containsKey("session_key")) {
   	            // 开始处理userInfo
   	            String openId = obj.get("openid").toString();
   	            WxUser WxUser =new WxUser();
   	            WxUser.setOpenid(openId);
   	            // 先查询openId存在不存在,存在不入库,不存在就入库
   	            igWuser=wxUserMapper.selectByOpenId(WxUser);
   	            if (igWuser != null) {
   	            	  Map<String,Object> resultMap=new HashMap<String,Object>();
   	  	            resultMap.put("igWuser", igWuser);
   	  	            String sessionkey= igJedisClientService.get(openId);
   	  	            resultMap.put("sessionKey", sessionkey);
   	  	            
   	  	          try { 
               	      String result = AesCbcUtil.decrypt(encryptedData, obj.getString("session_key"), iv, "UTF-8"); 
               	      if (null != result && result.length() > 0) { 
               	    	 igWuser=new WxUser();
               	        JSONObject userInfoJSON = JSON.parseObject(result); 
               	        igWuser.setNickname(userInfoJSON.getString("nickName"));
               	        igWuser.setOpenid(userInfoJSON.getString("openId"));
               	        igWuser.setGender(userInfoJSON.getString("gender"));
               	        igWuser.setCity(userInfoJSON.getString("city"));
               	        igWuser.setProvince( userInfoJSON.getString("province"));
               	        igWuser.setCountry(userInfoJSON.getString("country"));
               	        igWuser.setAvatarurl(userInfoJSON.getString("avatarUrl"));
               	        
               	        wxUserMapper.updateByPrimaryKeySelective(igWuser);
               	      } 
               	    } catch (Exception e) { 
               	      e.printStackTrace(); 
               	      return ResultUtil.fail("session_key错误,解密不正确");
               	    } 
   	  	          
   		            
   	  	            return ResultUtil.success(resultMap);
   	            } else {
   	            	try { 
   	            	      String result = AesCbcUtil.decrypt(encryptedData, obj.getString("session_key"), iv, "UTF-8"); 
   	            	      if (null != result && result.length() > 0) { 
   	            	    	 igWuser=new WxUser();
   	            	        JSONObject userInfoJSON = JSON.parseObject(result); 
   	            	        igWuser.setNickname(userInfoJSON.getString("nickName"));
   	            	        igWuser.setOpenid(userInfoJSON.getString("openId"));
   	            	        igWuser.setGender(userInfoJSON.getString("gender"));
   	            	        igWuser.setCity(userInfoJSON.getString("city"));
   	            	        igWuser.setProvince( userInfoJSON.getString("province"));
   	            	        igWuser.setCountry(userInfoJSON.getString("country"));
   	            	        igWuser.setAvatarurl(userInfoJSON.getString("avatarUrl"));
   	            	        igWuser.setUserId(UUID.randomUUID().toString());
   	            	        wxUserMapper.insertSelective(igWuser);
   	            	      } 
   	            	    } catch (Exception e) { 
   	            	      e.printStackTrace(); 
   	            	      return ResultUtil.fail("session_key错误,解密不正确");
   	            	    } 
   	            }
   	            // (1) 获得sessionkey
   	            String sessionKey = obj.get("session_key").toString();
   	            // (2) 得到sessionkey以后存到缓存,key值采用不会重复的uuid
   	            String rsession = UUID.randomUUID().toString();
   	            // (3) 首先根据openId,取出来之前存的openId对应的sessionKey的值。
   	            String oldSeesionKey = igJedisClientService.get(openId);
   	            if (oldSeesionKey != null && !"".equals(oldSeesionKey)) {
   	              // (4) 删除之前openId对应的缓存
   	            	igJedisClientService.del(oldSeesionKey);
   	            }
   	            // (5) 开始缓存新的sessionKey: key --> uuid, value --> sessionObj
   	            JSONObject sessionObj = new JSONObject();
   	            sessionObj.put("openId", openId);
   	            sessionObj.put("sessionKey", sessionKey);
   	            igJedisClientService.set(rsession, sessionObj.toString());
   	 
   	            // (6) 开始缓存新的openId与session对应关系 : key --> openId , value --> rsession
   	            igJedisClientService.set(openId, rsession);
   	
   	            // (7) 把新的sessionKey返回给小程序
   	            Map<String,Object> resultMap=new HashMap<String,Object>();
   	            resultMap.put("sessionKey", rsession);
   	            resultMap.put("igWuser", igWuser);
   	            
   	            return ResultUtil.success(resultMap);
   	          }
           }
          return null;
   	}
   }
   

4.接口

package com.system.service;
import com.system.entity.vo.ResultVo;
public interface AppLoginService {
	ResultVo loginByWeixin(String encryptedData, String iv, String code);
}

5.编写Controller层

	package com.system.controller;
	import ...

	/**
	* 小程序微信授权登录
	* @author ROG
	*
	*/
	@Controller
	@RequestMapping("visitor")
	public class AppLoginController {
		@Autowired
		private AppLoginService igLoginService;
		/**
		* 微信小程序登录
		* @throws Exception
		*/
		@RequestMapping(value="/loginByWX",method={RequestMethod.POST,RequestMethod.GET})
		@ResponseBody
		public ResultVo loginByWeixin(String encryptedData, String iv, String code) throws Exception {
			if(StringUtils.isEmpty(code)){
				return ResultUtil.fail("code没有传");
			}else{
				return igLoginService.loginByWeixin(encryptedData,iv,code); 
			}
		}
	}

总结

微信登录业务逻辑

  • 新建数据库,头像使用图库
  • redis用来快速缓存前后端对应关系
  • http请求直接调包
本站总访问量

BUFF © 2018. All rights reserved.

Powered by Hydejack v8.1.1