SSM项目第3讲
in 语言/工程/算法
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自己添加
}
加入相关架包
首先在lib里面加架包
bcprov-jdk16-1.46.jar 传输加密解密类 httpclient-4.5.6。jar httpcore-4.4.10.jar httpmime-4.5.6.jar HTTP传输类 jedis-2.9.0.jar redis类
2.可知下面的工作分为三大部分:
- 微信小程序登录
- 设置HTTP传输
- 设置redis数据库
- 设置WeChat传输
设置HTTP传输
HTTP传输反馈类
- 在com.entity.vo下新建传输回馈实例类,ResultVo.java
HTTP工具类
- 在com.common.util下新建传输连接工具类,HttpUtil.java
HTTP处理工具类
- 在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请求直接调包