SpringBoot 中的微信登录、已有微信账号绑定用户名密码本地账号、加密解密字符串、分页、Echarts 图表、主从数据库读写分离拦截器、全局异常处理器
作者:互联网
1、微信登录
application.properties 配置
#微信相关
wechat.appid=wxd7f6c5b8899fba83
wechat.prefix=https://open.weixin.qq.com/connect/oauth2/authorize?appid=${wechat.appid}&redirect_uri=
wechat.middle=&response_type=code&scope=snsapi_userinfo&state=
wechat.suffix=#wechat_redirect
wechat.auth.url=http://o2o.yitiaojieinfo.com/o2o/shopadmin/addshopauthmap
wechat.login.url=http://o2o.yitiaojieinfo.com/o2o/wechatlogin/logincheck
wechat.exchange.url=http://o2o.yitiaojieinfo.com/o2o/shopadmin/exchangeaward
wechat.productmap.url=http://o2o.yitiaojieinfo.com/o2o/shopadmin/adduserproductmap
WechatAuth.java
package com.imooc.o2o.entity;
import java.util.Date;
/**
* 微信登录实体类
*/
public class WechatAuth {
// 主键ID
private Long wechatAuthId;
// 微信获取用户信息的凭证,对于某个公众号具有唯一性
private String openId;
// 创建时间
private Date createTime;
// 用户信息
private PersonInfo personInfo;
public Long getWechatAuthId() {
return wechatAuthId;
}
public void setWechatAuthId(Long wechatAuthId) {
this.wechatAuthId = wechatAuthId;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public PersonInfo getPersonInfo() {
return personInfo;
}
public void setPersonInfo(PersonInfo personInfo) {
this.personInfo = personInfo;
}
}
WechatUser.java
package com.imooc.o2o.dto;
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* 微信用户实体类
*/
public class WechatUser implements Serializable {
private static final long serialVersionUID = -4684067645282292327L;
// openId,标识该公众号下面的该用户的唯一Id
@JsonProperty("openid")
private String openId;
// 用户昵称
@JsonProperty("nickname")
private String nickName;
// 性别
@JsonProperty("sex")
private int sex;
// 省份
@JsonProperty("province")
private String province;
// 城市
@JsonProperty("city")
private String city;
// 区
@JsonProperty("country")
private String country;
// 头像图片地址
@JsonProperty("headimgurl")
private String headimgurl;
// 语言
@JsonProperty("language")
private String language;
// 用户权限,这里没什么作用
@JsonProperty("privilege")
private String[] privilege;
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public int getSex() {
return sex;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public String getLanguage() {
return language;
}
public void setLanguage(String language) {
this.language = language;
}
public String[] getPrivilege() {
return privilege;
}
public void setPrivilege(String[] privilege) {
this.privilege = privilege;
}
@Override
public String toString() {
return "openId:" + this.getOpenId() + ",nikename:" + this.getNickName();
}
}
WechatInfo.java
package com.imooc.o2o.dto;
/**
* 用来接收平台二维码的信息
*/
public class WechatInfo {
private Long customerId;
private Long productId;
private Long userAwardId;
private Long createTime;
private Long shopId;
public Long getCustomerId() {
return customerId;
}
public void setCustomerId(Long customerId) {
this.customerId = customerId;
}
public Long getProductId() {
return productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public Long getUserAwardId() {
return userAwardId;
}
public void setUserAwardId(Long userAwardId) {
this.userAwardId = userAwardId;
}
public Long getShopId() {
return shopId;
}
public void setShopId(Long shopId) {
this.shopId = shopId;
}
public Long getCreateTime() {
return createTime;
}
public void setCreateTime(Long createTime) {
this.createTime = createTime;
}
}
UserAccessToken.java
package com.imooc.o2o.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* 用户授权token
*/
public class UserAccessToken {
// 获取到的凭证
@JsonProperty("access_token")
private String accessToken;
// 凭证有效时间,单位:秒
@JsonProperty("expires_in")
private String expiresIn;
// 表示更新令牌,用来获取下一次的访问令牌,这里没太大用处
@JsonProperty("refresh_token")
private String refreshToken;
// 该用户在此公众号下的身份标识,对于此微信号具有唯一性
@JsonProperty("openid")
private String openId;
// 表示权限范围,这里可省略
@JsonProperty("scope")
private String scope;
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public String getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(String expiresIn) {
this.expiresIn = expiresIn;
}
public String getRefreshToken() {
return refreshToken;
}
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
@Override
public String toString() {
return "accessToken:" + this.getAccessToken() + ",openId:" + this.getOpenId();
}
}
WechatAuthStateEnum.java
package com.imooc.o2o.enums;
public enum WechatAuthStateEnum {
LOGINFAIL(-1, "openId输入有误"), SUCCESS(0, "操作成功"), NULL_AUTH_INFO(-1006, "注册信息为空");
private int state;
private String stateInfo;
private WechatAuthStateEnum(int state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
public static WechatAuthStateEnum stateOf(int index) {
for (WechatAuthStateEnum state : values()) {
if (state.getState() == index) {
return state;
}
}
return null;
}
}
WechatAuthExecution.java
package com.imooc.o2o.dto;
import java.util.List;
import com.imooc.o2o.entity.WechatAuth;
import com.imooc.o2o.enums.WechatAuthStateEnum;
public class WechatAuthExecution {
// 结果状态
private int state;
// 状态标识
private String stateInfo;
private int count;
private WechatAuth wechatAuth;
private List<WechatAuth> wechatAuthList;
public WechatAuthExecution() {
}
// 失败的构造器
public WechatAuthExecution(WechatAuthStateEnum stateEnum) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
}
// 成功的构造器
public WechatAuthExecution(WechatAuthStateEnum stateEnum, WechatAuth wechatAuth) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.wechatAuth = wechatAuth;
}
// 成功的构造器
public WechatAuthExecution(WechatAuthStateEnum stateEnum,
List<WechatAuth> wechatAuthList) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.wechatAuthList = wechatAuthList;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public WechatAuth getWechatAuth() {
return wechatAuth;
}
public void setWechatAuth(WechatAuth wechatAuth) {
this.wechatAuth = wechatAuth;
}
public List<WechatAuth> getWechatAuthList() {
return wechatAuthList;
}
public void setWechatAuthList(List<WechatAuth> wechatAuthList) {
this.wechatAuthList = wechatAuthList;
}
}
WechatAuthOperationException.java
package com.imooc.o2o.exceptions;
public class WechatAuthOperationException extends RuntimeException {
private static final long serialVersionUID = -4290016045533442745L;
public WechatAuthOperationException(String msg) {
super(msg);
}
}
WechatAuthDao.java
package com.imooc.o2o.dao;
import com.imooc.o2o.entity.WechatAuth;
public interface WechatAuthDao {
/**
* 通过openId查询对应本平台的微信帐号
*
* @param openId
* @return
*/
WechatAuth queryWechatInfoByOpenId(String openId);
/**
* 添加对应本平台的微信帐号
*
* @param wechatAuth
* @return
*/
int insertWechatAuth(WechatAuth wechatAuth);
}
WechatAuthDao.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.imooc.o2o.dao.WechatAuthDao">
<resultMap id="wechatAuthResultMap" type="com.imooc.o2o.entity.WechatAuth">
<id column="wechat_auth_id" property="wechatAuthId" />
<result column="open_id" property="openId" />
<result column="create_time" property="createTime" />
<association property="personInfo" column="user_id"
javaType="com.imooc.o2o.entity.PersonInfo">
<id column="user_id" property="userId" />
<result column="name" property="name" />
<result column="gender" property="gender" />
<result column="email" property="email" />
<result column="profile_img" property="profileImg" />
<result column="user_type" property="userType" />
<result column="create_time" property="createTime" />
<result column="last_edit_time" property="lastEditTime" />
<result column="enable_status" property="enableStatus" />
</association>
</resultMap>
<select id="queryWechatInfoByOpenId" resultMap="wechatAuthResultMap"
parameterType="String">
SELECT
w.wechat_auth_id,
w.open_id,
w.create_time,
p.user_id,
p.name,
p.gender,
p.email,
p.profile_img,
p.user_type,
p.create_time,
p.last_edit_time,
p.enable_status
FROM
tb_wechat_auth w
LEFT JOIN
tb_person_info
p ON w.user_id =
p.user_id
WHERE
w.open_id =
#{openId}
</select>
<insert id="insertWechatAuth" parameterType="com.imooc.o2o.entity.WechatAuth"
useGeneratedKeys="true" keyProperty="wechatAuthId" keyColumn="wechat_auth_id">
INSERT
INTO
tb_wechat_auth(user_id,open_id,create_time)
VALUES
(#{personInfo.userId},#{openId},#{createTime})
</insert>
</mapper>
证书信任管理器(用于https请求)MyX509TrustManager.java
package com.imooc.o2o.util.wechat;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509TrustManager;
/**
* 证书信任管理器(用于https请求)
*/
public class MyX509TrustManager implements X509TrustManager {
/**
* 该方法检查客户端的证书,若不信任该证书则抛出异常。 由于我们不需要对客户端进行认证,因此我们只需要执行默认的信任管理器的这个方法。
* JSSE中,默认的信任管理器类为TrustManager
*/
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
/**
* 该方法检查服务器的证书,若不信任该证书同样抛出异常。通过自己实现该方法,可以使之信任我们指定的任何证书。
* 在实现该方法时,也可以简单的不做任何处理,即一个空的函数体,由于不会抛出异常,它就会信任任何证书。
*/
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
/**
* 返回受信任的X509证书数组
*/
public X509Certificate[] getAcceptedIssuers() {
return null;
}
}
微信请求校验工具类 SignUtil.java
package com.imooc.o2o.util.wechat;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
/**
* 微信请求校验工具类
*/
public class SignUtil {
// 与接口配置信息中的Token要一致
private static String token = "myo2o";
/**
* 验证签名
*
* @param signature
* @param timestamp
* @param nonce
* @return
*/
public static boolean checkSignature(String signature, String timestamp, String nonce) {
String[] arr = new String[] { token, timestamp, nonce };
// 将token、timestamp、nonce三个参数进行字典序排序
Arrays.sort(arr);
StringBuilder content = new StringBuilder();
for (int i = 0; i < arr.length; i++) {
content.append(arr[i]);
}
MessageDigest md = null;
String tmpStr = null;
try {
md = MessageDigest.getInstance("SHA-1");
// 将三个参数字符串拼接成一个字符串进行sha1加密
byte[] digest = md.digest(content.toString().getBytes());
tmpStr = byteToStr(digest);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
content = null;
// 将sha1加密后的字符串可与signature对比,标识该请求来源于微信
return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
}
/**
* 将字节数组转换为十六进制字符串
*
* @param byteArray
* @return
*/
private static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = 0; i < byteArray.length; i++) {
strDigest += byteToHexStr(byteArray[i]);
}
return strDigest;
}
/**
* 将字节转换为十六进制字符串
*
* @param mByte
* @return
*/
private static String byteToHexStr(byte mByte) {
char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[2];
tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
tempArr[1] = Digit[mByte & 0X0F];
String s = new String(tempArr);
return s;
}
}
微信工具类 WechatUtil.java
package com.imooc.o2o.util.wechat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.o2o.dto.UserAccessToken;
import com.imooc.o2o.dto.WechatUser;
import com.imooc.o2o.entity.PersonInfo;
/**
* 微信工具类
*/
public class WechatUtil {
private static Logger log = LoggerFactory.getLogger(WechatUtil.class);
/**
* 获取UserAccessToken实体类
*
* @param code
* @return
* @throws IOException
*/
public static UserAccessToken getUserAccessToken(String code) throws IOException {
// 测试号信息里的appId
String appId = "wxd7f6c5b8899fba83";
log.debug("appId:" + appId);
// 测试号信息里的appsecret
String appsecret = "665ae80dba31fc91ab6191e7da4d676d";
log.debug("secret:" + appsecret);
// 根据传入的code,拼接出访问微信定义好的接口的URL
String url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + appId + "&secret=" + appsecret
+ "&code=" + code + "&grant_type=authorization_code";
// 向相应URL发送请求获取token json字符串
String tokenStr = httpsRequest(url, "GET", null);
log.debug("userAccessToken:" + tokenStr);
UserAccessToken token = new UserAccessToken();
ObjectMapper objectMapper = new ObjectMapper();
try {
// 将json字符串转换成相应对象
token = objectMapper.readValue(tokenStr, UserAccessToken.class);
} catch (JsonParseException e) {
log.error("获取用户accessToken失败: " + e.getMessage());
e.printStackTrace();
} catch (JsonMappingException e) {
log.error("获取用户accessToken失败: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
log.error("获取用户accessToken失败: " + e.getMessage());
e.printStackTrace();
}
if (token == null) {
log.error("获取用户accessToken失败。");
return null;
}
return token;
}
/**
* 获取WechatUser实体类
*
* @param accessToken
* @param openId
* @return
*/
public static WechatUser getUserInfo(String accessToken, String openId) {
// 根据传入的accessToken以及openId拼接出访问微信定义的端口并获取用户信息的URL
String url = "https://api.weixin.qq.com/sns/userinfo?access_token=" + accessToken + "&openid=" + openId
+ "&lang=zh_CN";
// 访问该URL获取用户信息json 字符串
String userStr = httpsRequest(url, "GET", null);
log.debug("user info :" + userStr);
WechatUser user = new WechatUser();
ObjectMapper objectMapper = new ObjectMapper();
try {
// 将json字符串转换成相应对象
user = objectMapper.readValue(userStr, WechatUser.class);
} catch (JsonParseException e) {
log.error("获取用户信息失败: " + e.getMessage());
e.printStackTrace();
} catch (JsonMappingException e) {
log.error("获取用户信息失败: " + e.getMessage());
e.printStackTrace();
} catch (IOException e) {
log.error("获取用户信息失败: " + e.getMessage());
e.printStackTrace();
}
if (user == null) {
log.error("获取用户信息失败。");
return null;
}
return user;
}
/**
* 将WechatUser里的信息转换成PersonInfo的信息并返回PersonInfo实体类
*
* @param user
* @return
*/
public static PersonInfo getPersonInfoFromRequest(WechatUser user) {
PersonInfo personInfo = new PersonInfo();
personInfo.setName(user.getNickName());
personInfo.setGender(user.getSex() + "");
personInfo.setProfileImg(user.getHeadimgurl());
personInfo.setEnableStatus(1);
return personInfo;
}
/**
* 发起https请求并获取结果
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return json字符串
*/
public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
StringBuffer buffer = new StringBuffer();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
log.debug("https buffer:" + buffer.toString());
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return buffer.toString();
}
}
WechatAuthService.java
package com.imooc.o2o.service;
import com.imooc.o2o.dto.WechatAuthExecution;
import com.imooc.o2o.entity.WechatAuth;
import com.imooc.o2o.exceptions.WechatAuthOperationException;
public interface WechatAuthService {
/**
* 通过openId查找平台对应的微信帐号
*
* @param openId
* @return
*/
WechatAuth getWechatAuthByOpenId(String openId);
/**
* 注册本平台的微信帐号
*
* @param wechatAuth
* @param profileImg
* @return
* @throws RuntimeException
*/
WechatAuthExecution register(WechatAuth wechatAuth) throws WechatAuthOperationException;
}
WechatAuthServiceImpl.java
package com.imooc.o2o.service.impl;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.imooc.o2o.dao.PersonInfoDao;
import com.imooc.o2o.dao.WechatAuthDao;
import com.imooc.o2o.dto.WechatAuthExecution;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.WechatAuth;
import com.imooc.o2o.enums.WechatAuthStateEnum;
import com.imooc.o2o.exceptions.WechatAuthOperationException;
import com.imooc.o2o.service.WechatAuthService;
@Service
public class WechatAuthServiceImpl implements WechatAuthService {
private static Logger log = LoggerFactory.getLogger(WechatAuthServiceImpl.class);
@Autowired
private WechatAuthDao wechatAuthDao;
@Autowired
private PersonInfoDao personInfoDao;
@Override
public WechatAuth getWechatAuthByOpenId(String openId) {
return wechatAuthDao.queryWechatInfoByOpenId(openId);
}
@Override
@Transactional
public WechatAuthExecution register(WechatAuth wechatAuth) throws WechatAuthOperationException {
//空值判断
if (wechatAuth == null || wechatAuth.getOpenId() == null) {
return new WechatAuthExecution(WechatAuthStateEnum.NULL_AUTH_INFO);
}
try {
//设置创建时间
wechatAuth.setCreateTime(new Date());
//如果微信帐号里夹带着用户信息并且用户Id为空,则认为该用户第一次使用平台(且通过微信登录)
//则自动创建用户信息
if (wechatAuth.getPersonInfo() != null && wechatAuth.getPersonInfo().getUserId() == null) {
try {
wechatAuth.getPersonInfo().setCreateTime(new Date());
wechatAuth.getPersonInfo().setEnableStatus(1);
PersonInfo personInfo = wechatAuth.getPersonInfo();
int effectedNum = personInfoDao.insertPersonInfo(personInfo);
wechatAuth.setPersonInfo(personInfo);
if (effectedNum <= 0) {
throw new WechatAuthOperationException("添加用户信息失败");
}
} catch (Exception e) {
log.error("insertPersonInfo error:" + e.toString());
throw new WechatAuthOperationException("insertPersonInfo error: " + e.getMessage());
}
}
//创建专属于本平台的微信帐号
int effectedNum = wechatAuthDao.insertWechatAuth(wechatAuth);
if (effectedNum <= 0) {
throw new WechatAuthOperationException("帐号创建失败");
} else {
return new WechatAuthExecution(WechatAuthStateEnum.SUCCESS, wechatAuth);
}
} catch (Exception e) {
log.error("insertWechatAuth error:" + e.toString());
throw new WechatAuthOperationException("insertWechatAuth error: " + e.getMessage());
}
}
}
WechatController.java
package com.imooc.o2o.web.wechat;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.imooc.o2o.util.wechat.SignUtil;
@Controller
@RequestMapping("wechat")
public class WechatController {
private static Logger log = LoggerFactory.getLogger(WechatController.class);
@RequestMapping(method = { RequestMethod.GET })
public void doGet(HttpServletRequest request, HttpServletResponse response) {
log.debug("weixin get...");
// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
String signature = request.getParameter("signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
// 随机字符串
String echostr = request.getParameter("echostr");
// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,表示接入成功,否则接入失败
PrintWriter out = null;
try {
out = response.getWriter();
if (SignUtil.checkSignature(signature, timestamp, nonce)) {
log.debug("weixin get success....");
out.print(echostr);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null)
out.close();
}
}
}
WechatLoginController.java
package com.imooc.o2o.web.wechat;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.imooc.o2o.dto.UserAccessToken;
import com.imooc.o2o.dto.WechatAuthExecution;
import com.imooc.o2o.dto.WechatUser;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.WechatAuth;
import com.imooc.o2o.enums.WechatAuthStateEnum;
import com.imooc.o2o.service.PersonInfoService;
import com.imooc.o2o.service.WechatAuthService;
import com.imooc.o2o.util.wechat.WechatUtil;
/**
* 获取关注公众号之后的微信用户信息的接口,如果在微信浏览器里访问
* https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxd7f6c5b8899fba83&redirect_uri=http://o2o.yitiaojieinfo.com/o2o/wechatlogin/logincheck&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect
* 则这里将会获取到code,之后再可以通过code获取到access_token 进而获取到用户信息
*
* @author xiangze
*
*/
@Controller
@RequestMapping("wechatlogin")
public class WechatLoginController {
private static Logger log = LoggerFactory.getLogger(WechatLoginController.class);
private static final String FRONTEND = "1";
private static final String SHOPEND = "2";
@Autowired
private PersonInfoService personInfoService;
@Autowired
private WechatAuthService wechatAuthService;
@RequestMapping(value = "/logincheck", method = { RequestMethod.GET })
public String doGet(HttpServletRequest request, HttpServletResponse response) {
log.debug("weixin login get...");
// 获取微信公众号传输过来的code,通过code可获取access_token,进而获取用户信息
String code = request.getParameter("code");
// 这个state可以用来传我们自定义的信息,方便程序调用,这里也可以不用
String roleType = request.getParameter("state");
log.debug("weixin login code:" + code);
WechatUser user = null;
String openId = null;
WechatAuth auth = null;
if (null != code) {
UserAccessToken token;
try {
// 通过code获取access_token
token = WechatUtil.getUserAccessToken(code);
log.debug("weixin login token:" + token.toString());
// 通过token获取accessToken
String accessToken = token.getAccessToken();
// 通过token获取openId
openId = token.getOpenId();
// 通过access_token和openId获取用户昵称等信息
user = WechatUtil.getUserInfo(accessToken, openId);
log.debug("weixin login user:" + user.toString());
request.getSession().setAttribute("openId", openId);
auth = wechatAuthService.getWechatAuthByOpenId(openId);
} catch (IOException e) {
log.error("error in getUserAccessToken or getUserInfo or findByOpenId: " + e.toString());
e.printStackTrace();
}
}
// 若微信帐号为空则需要注册微信帐号,同时注册用户信息
if (auth == null) {
PersonInfo personInfo = WechatUtil.getPersonInfoFromRequest(user);
auth = new WechatAuth();
auth.setOpenId(openId);
if (FRONTEND.equals(roleType)) {
personInfo.setUserType(1);
} else {
personInfo.setUserType(2);
}
auth.setPersonInfo(personInfo);
WechatAuthExecution we = wechatAuthService.register(auth);
if (we.getState() != WechatAuthStateEnum.SUCCESS.getState()) {
return null;
} else {
personInfo = personInfoService.getPersonInfoById(auth.getPersonInfo().getUserId());
request.getSession().setAttribute("user", personInfo);
}
} else {
request.getSession().setAttribute("user", auth.getPersonInfo());
}
// 若用户点击的是前端展示系统按钮则进入前端展示系统
if (FRONTEND.equals(roleType)) {
return "frontend/index";
} else {
return "shop/shoplist";
}
}
}
2、已有微信账号绑定用户名密码本地账号
LocalAuth.java
package com.imooc.o2o.entity;
import java.util.Date;
/**
* 本地验证实体类,主要用来做帐号密码的登录
*
* @author xiangze
*
*/
public class LocalAuth {
// 主键ID
private Long localAuthId;
// 帐号
private String username;
// 密码
private String password;
// 创建时间
private Date createTime;
// 最近一次的更新时间
private Date lastEditTime;
// 个人信息,关系为一一对应
private PersonInfo personInfo;
public Long getLocalAuthId() {
return localAuthId;
}
public void setLocalAuthId(Long localAuthId) {
this.localAuthId = localAuthId;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getLastEditTime() {
return lastEditTime;
}
public void setLastEditTime(Date lastEditTime) {
this.lastEditTime = lastEditTime;
}
public PersonInfo getPersonInfo() {
return personInfo;
}
public void setPersonInfo(PersonInfo personInfo) {
this.personInfo = personInfo;
}
}
LocalAuthDao.java
package com.imooc.o2o.dao;
import java.util.Date;
import org.apache.ibatis.annotations.Param;
import com.imooc.o2o.entity.LocalAuth;
public interface LocalAuthDao {
/**
* 通过帐号和密码查询对应信息,登录用
*
* @param username
* @param password
* @return
*/
LocalAuth queryLocalByUserNameAndPwd(@Param("username") String username, @Param("password") String password);
/**
* 通过用户Id查询对应localauth
*
* @param userId
* @return
*/
LocalAuth queryLocalByUserId(@Param("userId") long userId);
/**
* 添加平台帐号
*
* @param localAuth
* @return
*/
int insertLocalAuth(LocalAuth localAuth);
/**
* 通过userId,username,password更改密码
*
* @param localAuth
* @return
*/
int updateLocalAuth(@Param("userId") Long userId, @Param("username") String username,
@Param("password") String password, @Param("newPassword") String newPassword,
@Param("lastEditTime") Date lastEditTime);
}
LocalAuthDao.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.imooc.o2o.dao.LocalAuthDao">
<resultMap id="localAuthResultMap" type="com.imooc.o2o.entity.LocalAuth">
<id column="local_auth_id" property="localAuthId" />
<result column="username" property="username" />
<result column="password" property="password" />
<result column="create_time" property="createTime" />
<result column="last_edit_time" property="lastEditTime" />
<association property="personInfo" column="user_id"
javaType="com.imooc.o2o.entity.PersonInfo">
<id column="user_id" property="userId" />
<result column="name" property="name" />
<result column="gender" property="gender" />
<result column="email" property="email" />
<result column="profile_img" property="profileImg" />
<result column="user_type" property="userType" />
<result column="create_time" property="createTime" />
<result column="last_edit_time" property="lastEditTime" />
<result column="enable_status" property="enableStatus" />
</association>
</resultMap>
<select id="queryLocalByUserNameAndPwd" resultMap="localAuthResultMap"
parameterType="String">
SELECT
l.local_auth_id,
l.username,
l.password,
l.create_time,
l.last_edit_time,
p.user_id,
p.name,
p.gender,
p.email,
p.profile_img,
p.user_type,
p.create_time,
p.last_edit_time,
p.enable_status
FROM
tb_local_auth l
LEFT
JOIN
tb_person_info
p ON l.user_id
=
p.user_id
WHERE
l.username =
#{username}
AND
l.password = #{password}
</select>
<select id="queryLocalByUserId" resultMap="localAuthResultMap"
parameterType="long">
SELECT
l.local_auth_id,
l.username,
l.password,
l.create_time,
l.last_edit_time,
p.user_id,
p.name,
p.gender,
p.email,
p.profile_img,
p.user_type,
p.create_time,
p.last_edit_time,
p.enable_status
FROM
tb_local_auth l
LEFT
JOIN
tb_person_info
p ON l.user_id
=
p.user_id
WHERE
l.user_id =
#{userId}
</select>
<insert id="insertLocalAuth" parameterType="com.imooc.o2o.entity.LocalAuth"
useGeneratedKeys="true" keyProperty="localAuthId" keyColumn="local_auth_id">
INSERT
INTO
tb_local_auth(username,password,user_id,create_time,last_edit_time)
VALUES
(#{username},#{password},#{personInfo.userId},#{createTime},#{lastEditTime})
</insert>
<update id="updateLocalAuth">
update tb_local_auth
<set>
<if test="newPassword != null">password=#{newPassword},</if>
<if test="lastEditTime != null">last_edit_time=#{lastEditTime}</if>
</set>
where user_id=#{userId}
AND username=#{username}
AND
password=#{password}
</update>
</mapper>
LocalAuthStateEnum.java
package com.imooc.o2o.enums;
public enum LocalAuthStateEnum {
LOGINFAIL(-1, "密码或帐号输入有误"), SUCCESS(0, "操作成功"), NULL_AUTH_INFO(-1006,
"注册信息为空"), ONLY_ONE_ACCOUNT(-1007,"最多只能绑定一个本地帐号");
private int state;
private String stateInfo;
private LocalAuthStateEnum(int state, String stateInfo) {
this.state = state;
this.stateInfo = stateInfo;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
public static LocalAuthStateEnum stateOf(int index) {
for (LocalAuthStateEnum state : values()) {
if (state.getState() == index) {
return state;
}
}
return null;
}
}
LocalAuthExecution.java
package com.imooc.o2o.dto;
import java.util.List;
import com.imooc.o2o.entity.LocalAuth;
import com.imooc.o2o.enums.LocalAuthStateEnum;
public class LocalAuthExecution {
// 结果状态
private int state;
// 状态标识
private String stateInfo;
private int count;
private LocalAuth localAuth;
private List<LocalAuth> localAuthList;
public LocalAuthExecution() {
}
// 失败的构造器
public LocalAuthExecution(LocalAuthStateEnum stateEnum) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
}
// 成功的构造器
public LocalAuthExecution(LocalAuthStateEnum stateEnum, LocalAuth localAuth) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.localAuth = localAuth;
}
// 成功的构造器
public LocalAuthExecution(LocalAuthStateEnum stateEnum,
List<LocalAuth> localAuthList) {
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.localAuthList = localAuthList;
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
public String getStateInfo() {
return stateInfo;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public LocalAuth getLocalAuth() {
return localAuth;
}
public void setLocalAuth(LocalAuth localAuth) {
this.localAuth = localAuth;
}
public List<LocalAuth> getLocalAuthList() {
return localAuthList;
}
public void setLocalAuthList(List<LocalAuth> localAuthList) {
this.localAuthList = localAuthList;
}
}
LocalAuthOperationException.java
package com.imooc.o2o.exceptions;
public class LocalAuthOperationException extends RuntimeException {
private static final long serialVersionUID = -8260236137099919700L;
public LocalAuthOperationException(String msg) {
super(msg);
}
}
LocalAuthService.java
package com.imooc.o2o.service;
import com.imooc.o2o.dto.LocalAuthExecution;
import com.imooc.o2o.entity.LocalAuth;
import com.imooc.o2o.exceptions.LocalAuthOperationException;
public interface LocalAuthService {
/**
* 通过帐号和密码获取平台帐号信息
*
* @param userName
* @return
*/
LocalAuth getLocalAuthByUsernameAndPwd(String userName, String password);
/**
* 通过userId获取平台帐号信息
*
* @param userId
* @return
*/
LocalAuth getLocalAuthByUserId(long userId);
/**
* 绑定微信,生成平台专属的帐号
*
* @param localAuth
* @return
* @throws RuntimeException
*/
LocalAuthExecution bindLocalAuth(LocalAuth localAuth) throws LocalAuthOperationException;
/**
* 修改平台帐号的登录密码
*
* @param localAuthId
* @param userName
* @param password
* @param newPassword
* @param lastEditTime
* @return
*/
LocalAuthExecution modifyLocalAuth(Long userId, String username, String password, String newPassword)
throws LocalAuthOperationException;
}
LocalAuthServiceImpl.java
package com.imooc.o2o.service.impl;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.imooc.o2o.dao.LocalAuthDao;
import com.imooc.o2o.dto.LocalAuthExecution;
import com.imooc.o2o.entity.LocalAuth;
import com.imooc.o2o.enums.LocalAuthStateEnum;
import com.imooc.o2o.exceptions.LocalAuthOperationException;
import com.imooc.o2o.service.LocalAuthService;
import com.imooc.o2o.util.MD5;
@Service
public class LocalAuthServiceImpl implements LocalAuthService {
@Autowired
private LocalAuthDao localAuthDao;
@Override
public LocalAuth getLocalAuthByUsernameAndPwd(String username, String password) {
return localAuthDao.queryLocalByUserNameAndPwd(username, MD5.getMd5(password));
}
@Override
public LocalAuth getLocalAuthByUserId(long userId) {
return localAuthDao.queryLocalByUserId(userId);
}
@Override
@Transactional
public LocalAuthExecution bindLocalAuth(LocalAuth localAuth) throws LocalAuthOperationException {
// 空值判断,传入的localAuth 帐号密码,用户信息特别是userId不能为空,否则直接返回错误
if (localAuth == null || localAuth.getPassword() == null || localAuth.getUsername() == null
|| localAuth.getPersonInfo() == null || localAuth.getPersonInfo().getUserId() == null) {
return new LocalAuthExecution(LocalAuthStateEnum.NULL_AUTH_INFO);
}
// 查询此用户是否已绑定过平台帐号
LocalAuth tempAuth = localAuthDao.queryLocalByUserId(localAuth.getPersonInfo().getUserId());
if (tempAuth != null) {
// 如果绑定过则直接退出,以保证平台帐号的唯一性
return new LocalAuthExecution(LocalAuthStateEnum.ONLY_ONE_ACCOUNT);
}
try {
// 如果之前没有绑定过平台帐号,则创建一个平台帐号与该用户绑定
localAuth.setCreateTime(new Date());
localAuth.setLastEditTime(new Date());
// 对密码进行MD5加密
localAuth.setPassword(MD5.getMd5(localAuth.getPassword()));
int effectedNum = localAuthDao.insertLocalAuth(localAuth);
// 判断创建是否成功
if (effectedNum <= 0) {
throw new LocalAuthOperationException("帐号绑定失败");
} else {
return new LocalAuthExecution(LocalAuthStateEnum.SUCCESS, localAuth);
}
} catch (Exception e) {
throw new LocalAuthOperationException("insertLocalAuth error: " + e.getMessage());
}
}
@Override
@Transactional
public LocalAuthExecution modifyLocalAuth(Long userId, String userName, String password, String newPassword)
throws LocalAuthOperationException {
// 非空判断,判断传入的用户Id,帐号,新旧密码是否为空,新旧密码是否相同,若不满足条件则返回错误信息
if (userId != null && userName != null && password != null && newPassword != null
&& !password.equals(newPassword)) {
try {
// 更新密码,并对新密码进行MD5加密
int effectedNum = localAuthDao.updateLocalAuth(userId, userName, MD5.getMd5(password),
MD5.getMd5(newPassword), new Date());
// 判断更新是否成功
if (effectedNum <= 0) {
throw new LocalAuthOperationException("更新密码失败");
}
return new LocalAuthExecution(LocalAuthStateEnum.SUCCESS);
} catch (Exception e) {
throw new LocalAuthOperationException("更新密码失败:" + e.toString());
}
} else {
return new LocalAuthExecution(LocalAuthStateEnum.NULL_AUTH_INFO);
}
}
}
LocalController.java
package com.imooc.o2o.web.local;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
@RequestMapping("/local")
public class LocalController {
/**
* 绑定帐号页路由
*
* @return
*/
@RequestMapping(value = "/accountbind", method = RequestMethod.GET)
private String accountbind() {
return "local/accountbind";
}
/**
* 修改密码页路由
*
* @return
*/
@RequestMapping(value = "/changepsw", method = RequestMethod.GET)
private String changepsw() {
return "local/changepsw";
}
/**
* 登录页路由
*
* @return
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
private String login() {
return "local/login";
}
}
LocalAuthController.java
package com.imooc.o2o.web.local;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.imooc.o2o.dto.LocalAuthExecution;
import com.imooc.o2o.entity.LocalAuth;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.enums.LocalAuthStateEnum;
import com.imooc.o2o.exceptions.LocalAuthOperationException;
import com.imooc.o2o.service.LocalAuthService;
import com.imooc.o2o.util.CodeUtil;
import com.imooc.o2o.util.HttpServletRequestUtil;
@Controller
@RequestMapping(value = "local", method = { RequestMethod.GET, RequestMethod.POST })
public class LocalAuthController {
@Autowired
private LocalAuthService localAuthService;
@RequestMapping(value = "/bindlocalauth", method = RequestMethod.POST)
@ResponseBody
/**
* 将用户信息与平台帐号绑定
*
* @param request
* @return
*/
private Map<String, Object> bindLocalAuth(HttpServletRequest request) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 验证码校验
if (!CodeUtil.checkVerifyCode(request)) {
modelMap.put("success", false);
modelMap.put("errMsg", "输入了错误的验证码");
return modelMap;
}
// 获取输入的帐号
String userName = HttpServletRequestUtil.getString(request, "userName");
// 获取输入的密码
String password = HttpServletRequestUtil.getString(request, "password");
// 从session中获取当前用户信息(用户一旦通过微信登录之后,便能获取到用户的信息)
PersonInfo user = (PersonInfo) request.getSession().getAttribute("user");
// 非空判断,要求帐号密码以及当前的用户session非空
if (userName != null && password != null && user != null && user.getUserId() != null) {
// 创建LocalAuth对象并赋值
LocalAuth localAuth = new LocalAuth();
localAuth.setUsername(userName);
localAuth.setPassword(password);
localAuth.setPersonInfo(user);
// 绑定帐号
LocalAuthExecution le = localAuthService.bindLocalAuth(localAuth);
if (le.getState() == LocalAuthStateEnum.SUCCESS.getState()) {
modelMap.put("success", true);
} else {
modelMap.put("success", false);
modelMap.put("errMsg", le.getStateInfo());
}
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "用户名和密码均不能为空");
}
return modelMap;
}
@RequestMapping(value = "/changelocalpwd", method = RequestMethod.POST)
@ResponseBody
/**
* 修改密码
*
* @param request
* @return
*/
private Map<String, Object> changeLocalPwd(HttpServletRequest request) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 验证码校验
if (!CodeUtil.checkVerifyCode(request)) {
modelMap.put("success", false);
modelMap.put("errMsg", "输入了错误的验证码");
return modelMap;
}
// 获取帐号
String userName = HttpServletRequestUtil.getString(request, "userName");
// 获取原密码
String password = HttpServletRequestUtil.getString(request, "password");
// 获取新密码
String newPassword = HttpServletRequestUtil.getString(request, "newPassword");
// 从session中获取当前用户信息(用户一旦通过微信登录之后,便能获取到用户的信息)
PersonInfo user = (PersonInfo) request.getSession().getAttribute("user");
// 非空判断,要求帐号新旧密码以及当前的用户session非空,且新旧密码不相同
if (userName != null && password != null && newPassword != null && user != null && user.getUserId() != null
&& !password.equals(newPassword)) {
try {
// 查看原先帐号,看看与输入的帐号是否一致,不一致则认为是非法操作
LocalAuth localAuth = localAuthService.getLocalAuthByUserId(user.getUserId());
if (localAuth == null || !localAuth.getUsername().equals(userName)) {
// 不一致则直接退出
modelMap.put("success", false);
modelMap.put("errMsg", "输入的帐号非本次登录的帐号");
return modelMap;
}
// 修改平台帐号的用户密码
LocalAuthExecution le = localAuthService.modifyLocalAuth(user.getUserId(), userName, password,
newPassword);
if (le.getState() == LocalAuthStateEnum.SUCCESS.getState()) {
modelMap.put("success", true);
} else {
modelMap.put("success", false);
modelMap.put("errMsg", le.getStateInfo());
}
} catch (LocalAuthOperationException e) {
modelMap.put("success", false);
modelMap.put("errMsg", e.toString());
return modelMap;
}
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "请输入密码");
}
return modelMap;
}
@RequestMapping(value = "/logincheck", method = RequestMethod.POST)
@ResponseBody
private Map<String, Object> logincheck(HttpServletRequest request) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 获取是否需要进行验证码校验的标识符
boolean needVerify = HttpServletRequestUtil.getBoolean(request, "needVerify");
if (needVerify && !CodeUtil.checkVerifyCode(request)) {
modelMap.put("success", false);
modelMap.put("errMsg", "输入了错误的验证码");
return modelMap;
}
// 获取输入的帐号
String userName = HttpServletRequestUtil.getString(request, "userName");
// 获取输入的密码
String password = HttpServletRequestUtil.getString(request, "password");
// 非空校验
if (userName != null && password != null) {
// 传入帐号和密码去获取平台帐号信息
LocalAuth localAuth = localAuthService.getLocalAuthByUsernameAndPwd(userName, password);
if (localAuth != null) {
// 若能取到帐号信息则登录成功
modelMap.put("success", true);
// 同时在session里设置用户信息
request.getSession().setAttribute("user", localAuth.getPersonInfo());
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "用户名或密码错误");
}
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "用户名和密码均不能为空");
}
return modelMap;
}
@RequestMapping(value = "/logout", method = RequestMethod.POST)
@ResponseBody
/**
* 当用户点击登出按钮的时候注销session
*
* @param request
* @return
* @throws IOException
*/
private Map<String, Object> logout(HttpServletRequest request) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 将用户session置为空
request.getSession().setAttribute("user", null);
modelMap.put("success", true);
return modelMap;
}
}
3、加密解密字符串
配置文件中存放数据库连接字符串、用户名密码字符串加解密。
DataSourceConfiguration.java
package com.imooc.o2o.config.dao;
import java.beans.PropertyVetoException;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.imooc.o2o.util.DESUtil;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/**
* 配置datasource到ioc容器里面
*/
@Configuration
// 配置mybatis mapper的扫描路径
@MapperScan("com.imooc.o2o.dao")
public class DataSourceConfiguration {
@Value("${jdbc.driver}")
private String jdbcDriver;
@Value("${jdbc.url}")
private String jdbcUrl;
@Value("${jdbc.username}")
private String jdbcUsername;
@Value("${jdbc.password}")
private String jdbcPassword;
/**
* 生成与spring-dao.xml对应的bean dataSource
*
* @return
* @throws PropertyVetoException
*/
@Bean(name = "dataSource")
public ComboPooledDataSource createDataSource() throws PropertyVetoException {
// 生成datasource实例
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 跟配置文件一样设置以下信息
// 驱动
dataSource.setDriverClass(jdbcDriver);
// 数据库连接URL
dataSource.setJdbcUrl(jdbcUrl);
// 设置用户名
dataSource.setUser(DESUtil.getDecryptString(jdbcUsername));
// 设置用户密码
dataSource.setPassword(DESUtil.getDecryptString(jdbcPassword));
// 配置c3p0连接池的私有属性
// 连接池最大线程数
dataSource.setMaxPoolSize(30);
// 连接池最小线程数
dataSource.setMinPoolSize(10);
dataSource.setInitialPoolSize(10);
// 关闭连接后不自动commit
dataSource.setAutoCommitOnClose(false);
// 连接超时时间
dataSource.setCheckoutTimeout(10000);
// 连接失败重试次数
dataSource.setAcquireRetryAttempts(2);
return dataSource;
}
}
DESUtil.java
package com.imooc.o2o.util;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* DES是一种对称加密算法,所谓对称加密算法即:加密和解密使用相同密钥的算法。
*/
public class DESUtil {
private static Key key;
// 设置密钥key
private static String KEY_STR = "myKey";
private static String CHARSETNAME = "UTF-8";
private static String ALGORITHM = "DES";
static {
try {
// 生成DES算法对象
KeyGenerator generator = KeyGenerator.getInstance(ALGORITHM);
// 运用SHA1安全策略
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
// 设置上密钥种子
secureRandom.setSeed(KEY_STR.getBytes());
// 初始化基于SHA1的算法对象
generator.init(secureRandom);
// 生成密钥对象
key = generator.generateKey();
generator = null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取加密后的信息
*
* @param str
* @return
*/
public static String getEncryptString(String str) {
// 基于BASE64编码,接收byte[]并转换成String
BASE64Encoder base64encoder = new BASE64Encoder();
try {
// 按UTF8编码
byte[] bytes = str.getBytes(CHARSETNAME);
// 获取加密对象
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化密码信息
cipher.init(Cipher.ENCRYPT_MODE, key);
// 加密
byte[] doFinal = cipher.doFinal(bytes);
// byte[]to encode好的String并返回
return base64encoder.encode(doFinal);
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException(e);
}
}
/**
* 获取解密之后的信息
*
* @param str
* @return
*/
public static String getDecryptString(String str) {
// 基于BASE64编码,接收byte[]并转换成String
BASE64Decoder base64decoder = new BASE64Decoder();
try {
// 将字符串decode成byte[]
byte[] bytes = base64decoder.decodeBuffer(str);
// 获取解密对象
Cipher cipher = Cipher.getInstance(ALGORITHM);
// 初始化解密信息
cipher.init(Cipher.DECRYPT_MODE, key);
// 解密
byte[] doFinal = cipher.doFinal(bytes);
// 返回解密之后的信息
return new String(doFinal, CHARSETNAME);
} catch (Exception e) {
// TODO: handle exception
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
System.out.println(getEncryptString("root"));
System.out.println(getEncryptString("Xiangze230!"));
}
}
EncryptPropertyPlaceholderConfigurer.java
package com.imooc.o2o.util;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
public class EncryptPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
// 需要加密的字段数组
private String[] encryptPropNames = { "jdbc.username", "jdbc.password" };
/**
* 对关键的属性进行转换
*/
@Override
protected String convertProperty(String propertyName, String propertyValue) {
if (isEncryptProp(propertyName)) {
// 对已加密的字段进行解密工作
String decryptValue = DESUtil.getDecryptString(propertyValue);
return decryptValue;
} else {
return propertyValue;
}
}
/**
* 该属性是否已加密
*
* @param propertyName
* @return
*/
private boolean isEncryptProp(String propertyName) {
// 若等于需要加密的field,则进行加密
for (String encryptpropertyName : encryptPropNames) {
if (encryptpropertyName.equals(propertyName))
return true;
}
return false;
}
}
MD5.java
package com.imooc.o2o.util;
import java.security.MessageDigest;
/**
* MD5加密
*/
public class MD5 {
/**
* 对传入的String进行MD5加密
*
* @param s
* @return
*/
public static final String getMd5(String s) {
// 16进制数组
char hexDigits[] = { '5', '0', '5', '6', '2', '9', '6', '2', '5', 'q', 'b', 'l', 'e', 's', 's', 'y' };
try {
char str[];
// 将传入的字符串转换成byte数组
byte strTemp[] = s.getBytes();
// 获取MD5加密对象
MessageDigest mdTemp = MessageDigest.getInstance("MD5");
// 传入需要加密的目标数组
mdTemp.update(strTemp);
// 获取加密后的数组
byte md[] = mdTemp.digest();
int j = md.length;
str = new char[j * 2];
int k = 0;
// 将数组做位移
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
// 转换成String并返回
return new String(str);
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
System.out.println(MD5.getMd5("123456"));
}
}
4、分页
PageCalculator.java
package com.imooc.o2o.util;
public class PageCalculator {
public static int calculateRowIndex(int pageIndex, int pageSize) {
return (pageIndex > 0) ? (pageIndex - 1) * pageSize : 0;
}
}
ProductServiceImpl.java
ackage com.imooc.o2o.service.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.imooc.o2o.dao.ProductDao;
import com.imooc.o2o.dao.ProductImgDao;
import com.imooc.o2o.dto.ProductExecution;
import com.imooc.o2o.entity.Product;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDao productDao;
@Autowired
private ProductImgDao productImgDao;
@Override
public ProductExecution getProductList(Product productCondition, int pageIndex, int pageSize) {
// 页码转换成数据库的行码,并调用dao层取回指定页码的商品列表
int rowIndex = PageCalculator.calculateRowIndex(pageIndex, pageSize);
List<Product> productList = productDao.queryProductList(productCondition, rowIndex, pageSize);
// 基于同样的查询条件返回该查询条件下的商品总数
int count = productDao.queryProductCount(productCondition);
ProductExecution pe = new ProductExecution();
pe.setProductList(productList);
pe.setCount(count);
return pe;
}
@Override
public Product getProductById(long productId) {
return productDao.queryProductById(productId);
}
}
5、Echarts 图表
EchartSeries.java
package com.imooc.o2o.dto;
import java.util.List;
/**
* 迎合echart里的series项
*/
public class EchartSeries {
private String name;
private String type = "bar";
private List<Integer> data;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Integer> getData() {
return data;
}
public void setData(List<Integer> data) {
this.data = data;
}
public String getType() {
return type;
}
}
EchartXAxis.java
package com.imooc.o2o.dto;
import java.util.HashSet;
/**
* 迎合echart里的xAxis项
*/
public class EchartXAxis {
private String type = "category";
//为了去重
private HashSet<String> data;
public HashSet<String> getData() {
return data;
}
public void setData(HashSet<String> data) {
this.data = data;
}
public String getType() {
return type;
}
}
UserProductManagementController.java
package com.imooc.o2o.web.shopadmin;
import java.io.IOException;
import java.net.URLDecoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.imooc.o2o.dto.EchartSeries;
import com.imooc.o2o.dto.EchartXAxis;
import com.imooc.o2o.dto.ShopAuthMapExecution;
import com.imooc.o2o.dto.UserAccessToken;
import com.imooc.o2o.dto.UserProductMapExecution;
import com.imooc.o2o.dto.WechatInfo;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.Product;
import com.imooc.o2o.entity.ProductSellDaily;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.entity.ShopAuthMap;
import com.imooc.o2o.entity.UserProductMap;
import com.imooc.o2o.entity.WechatAuth;
import com.imooc.o2o.enums.UserProductMapStateEnum;
import com.imooc.o2o.service.ProductSellDailyService;
import com.imooc.o2o.service.ProductService;
import com.imooc.o2o.service.ShopAuthMapService;
import com.imooc.o2o.service.UserProductMapService;
import com.imooc.o2o.service.WechatAuthService;
import com.imooc.o2o.util.HttpServletRequestUtil;
import com.imooc.o2o.util.wechat.WechatUtil;
@Controller
@RequestMapping("/shopadmin")
public class UserProductManagementController {
@Autowired
private UserProductMapService userProductMapService;
@Autowired
private ProductSellDailyService productSellDailyService;
@Autowired
private WechatAuthService wechatAuthService;
@Autowired
private ShopAuthMapService shopAuthMapService;
@Autowired
private ProductService productService;
@RequestMapping(value = "/listuserproductmapsbyshop", method = RequestMethod.GET)
@ResponseBody
private Map<String, Object> listUserProductMapsByShop(HttpServletRequest request) {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 获取分页信息
int pageIndex = HttpServletRequestUtil.getInt(request, "pageIndex");
int pageSize = HttpServletRequestUtil.getInt(request, "pageSize");
// 获取当前的店铺信息
Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
// 空值校验,主要确保shopId不为空
if ((pageIndex > -1) && (pageSize > -1) && (currentShop != null) && (currentShop.getShopId() != null)) {
// 添加查询条件
UserProductMap userProductMapCondition = new UserProductMap();
userProductMapCondition.setShop(currentShop);
String productName = HttpServletRequestUtil.getString(request, "productName");
if (productName != null) {
// 若前端想按照商品名模糊查询,则传入productName
Product product = new Product();
product.setProductName(productName);
userProductMapCondition.setProduct(product);
}
// 根据传入的查询条件获取该店铺的商品销售情况
UserProductMapExecution ue = userProductMapService.listUserProductMap(userProductMapCondition, pageIndex,
pageSize);
modelMap.put("userProductMapList", ue.getUserProductMapList());
modelMap.put("count", ue.getCount());
modelMap.put("success", true);
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "empty pageSize or pageIndex or shopId");
}
return modelMap;
}
@RequestMapping(value = "/listproductselldailyinfobyshop", method = RequestMethod.GET)
@ResponseBody
private Map<String, Object> listProductSellDailyInfobyShop(HttpServletRequest request) throws ParseException {
Map<String, Object> modelMap = new HashMap<String, Object>();
// 获取当前的店铺信息
Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
// 空值校验,主要确保shopId不为空
if ((currentShop != null) && (currentShop.getShopId() != null)) {
// 添加查询条件
ProductSellDaily productSellDailyCondition = new ProductSellDaily();
productSellDailyCondition.setShop(currentShop);
Calendar calendar = Calendar.getInstance();
// 获取昨天的日期
calendar.add(Calendar.DATE, -1);
Date endTime = calendar.getTime();
// 获取七天前的日期
calendar.add(Calendar.DATE, -6);
Date beginTime = calendar.getTime();
// 根据传入的查询条件获取该店铺的商品销售情况
List<ProductSellDaily> productSellDailyList = productSellDailyService
.listProductSellDaily(productSellDailyCondition, beginTime, endTime);
// 指定日期格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
// 商品名列表,保证唯一性
LinkedHashSet<String> legendData = new LinkedHashSet<String>();
// x轴数据
LinkedHashSet<String> xData = new LinkedHashSet<String>();
// 定义series
List<EchartSeries> series = new ArrayList<EchartSeries>();
// 日销量列表
List<Integer> totalList = new ArrayList<Integer>();
// 当前商品名,默认为空
String currentProductName = "";
for (int i = 0; i < productSellDailyList.size(); i++) {
ProductSellDaily productSellDaily = productSellDailyList.get(i);
// 自动去重
legendData.add(productSellDaily.getProduct().getProductName());
xData.add(sdf.format(productSellDaily.getCreateTime()));
if (!currentProductName.equals(productSellDaily.getProduct().getProductName())
&& !currentProductName.isEmpty()) {
// 如果currentProductName不等于获取的商品名,或者已遍历到列表的末尾,且currentProductName不为空,
// 则是遍历到下一个商品的日销量信息了, 将前一轮遍历的信息放入series当中,
// 包括了商品名以及与商品对应的统计日期以及当日销量
EchartSeries es = new EchartSeries();
es.setName(currentProductName);
es.setData(totalList.subList(0, totalList.size()));
series.add(es);
// 重置totalList
totalList = new ArrayList<Integer>();
// 变换下currentProductId为当前的productId
currentProductName = productSellDaily.getProduct().getProductName();
// 继续添加新的值
totalList.add(productSellDaily.getTotal());
} else {
// 如果还是当前的productId则继续添加新值
totalList.add(productSellDaily.getTotal());
currentProductName = productSellDaily.getProduct().getProductName();
}
// 队列之末,需要将最后的一个商品销量信息也添加上
if (i == productSellDailyList.size() - 1) {
EchartSeries es = new EchartSeries();
es.setName(currentProductName);
es.setData(totalList.subList(0, totalList.size()));
series.add(es);
}
}
modelMap.put("series", series);
modelMap.put("legendData", legendData);
// 拼接出xAxis
List<EchartXAxis> xAxis = new ArrayList<EchartXAxis>();
EchartXAxis exa = new EchartXAxis();
exa.setData(xData);
xAxis.add(exa);
modelMap.put("xAxis", xAxis);
modelMap.put("success", true);
} else {
modelMap.put("success", false);
modelMap.put("errMsg", "empty shopId");
}
return modelMap;
}
@RequestMapping(value = "/adduserproductmap", method = RequestMethod.GET)
private String addUserProductMap(HttpServletRequest request, HttpServletResponse response) throws IOException {
// 获取微信授权信息
WechatAuth auth = getOperatorInfo(request);
if (auth != null) {
PersonInfo operator = auth.getPersonInfo();
request.getSession().setAttribute("user", operator);
// 获取二维码里state携带的content信息并解码
String qrCodeinfo = new String(
URLDecoder.decode(HttpServletRequestUtil.getString(request, "state"), "UTF-8"));
ObjectMapper mapper = new ObjectMapper();
WechatInfo wechatInfo = null;
try {
// 将解码后的内容用aaa去替换掉之前生成二维码的时候加入的aaa前缀,转换成WechatInfo实体类
wechatInfo = mapper.readValue(qrCodeinfo.replace("aaa", "\""), WechatInfo.class);
} catch (Exception e) {
return "shop/operationfail";
}
// 校验二维码是否已经过期
if (!checkQRCodeInfo(wechatInfo)) {
return "shop/operationfail";
}
// 获取添加消费记录所需要的参数并组建成userproductmap实例
Long productId = wechatInfo.getProductId();
Long customerId = wechatInfo.getCustomerId();
UserProductMap userProductMap = compactUserProductMap4Add(customerId, productId, auth.getPersonInfo());
// 空值校验
if (userProductMap != null && customerId != -1) {
try {
if (!checkShopAuth(operator.getUserId(), userProductMap)) {
return "shop/operationfail";
}
// 添加消费记录
UserProductMapExecution se = userProductMapService.addUserProductMap(userProductMap);
if (se.getState() == UserProductMapStateEnum.SUCCESS.getState()) {
return "shop/operationsuccess";
}
} catch (RuntimeException e) {
return "shop/operationfail";
}
}
}
return "shop/operationfail";
}
/**
* 根据code获取UserAccessToken,进而通过token里的openId获取微信用户信息
*
* @param request
* @return
*/
private WechatAuth getOperatorInfo(HttpServletRequest request) {
String code = request.getParameter("code");
WechatAuth auth = null;
if (null != code) {
UserAccessToken token;
try {
token = WechatUtil.getUserAccessToken(code);
String openId = token.getOpenId();
request.getSession().setAttribute("openId", openId);
auth = wechatAuthService.getWechatAuthByOpenId(openId);
} catch (IOException e) {
e.printStackTrace();
}
}
return auth;
}
/**
* 根据二维码携带的createTime判断其是否超过了10分钟,超过十分钟则认为过期
*
* @param wechatInfo
* @return
*/
private boolean checkQRCodeInfo(WechatInfo wechatInfo) {
if (wechatInfo != null && wechatInfo.getProductId() != null && wechatInfo.getCustomerId() != null
&& wechatInfo.getCreateTime() != null) {
long nowTime = System.currentTimeMillis();
if ((nowTime - wechatInfo.getCreateTime()) <= 600000) {
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* 根据传入的customerId, productId以及操作员信息组建用户消费记录
*
* @param customerId
* @param productId
* @param operator
* @return
*/
private UserProductMap compactUserProductMap4Add(Long customerId, Long productId, PersonInfo operator) {
UserProductMap userProductMap = null;
if (customerId != null && productId != null) {
userProductMap = new UserProductMap();
PersonInfo customer = new PersonInfo();
customer.setUserId(customerId);
// 主要为了获取商品积分
Product product = productService.getProductById(productId);
userProductMap.setProduct(product);
userProductMap.setShop(product.getShop());
userProductMap.setUser(customer);
userProductMap.setPoint(product.getPoint());
userProductMap.setCreateTime(new Date());
userProductMap.setOperator(operator);
}
return userProductMap;
}
/**
* 检查扫码的人员是否有操作权限
*
* @param userId
* @param userProductMap
* @return
*/
private boolean checkShopAuth(long userId, UserProductMap userProductMap) {
// 获取该店铺的所有授权信息
ShopAuthMapExecution shopAuthMapExecution = shopAuthMapService
.listShopAuthMapByShopId(userProductMap.getShop().getShopId(), 1, 1000);
for (ShopAuthMap shopAuthMap : shopAuthMapExecution.getShopAuthMapList()) {
// 看看是否给过该人员进行授权
if (shopAuthMap.getEmployee().getUserId() == userId) {
return true;
}
}
return false;
}
}
6、主从数据库读写分离拦截器
DynamicDataSource.java
package com.imooc.o2o.dao.split;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource{
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDbType();
}
}
DynamicDataSourceHolder.java
package com.imooc.o2o.dao.split;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DynamicDataSourceHolder {
private static Logger logger = LoggerFactory.getLogger(DynamicDataSourceHolder.class);
private static ThreadLocal<String> contextHolder = new ThreadLocal<String>();
public static final String DB_MASTER = "master";
public static final String DB_SLAVE = "slave";
public static String getDbType() {
String db = contextHolder.get();
if (db == null) {
db = DB_MASTER;
}
return db;
}
/**
* 设置线程的dbType
*
* @param str
*/
public static void setDbType(String str) {
logger.debug("所使用的数据源为:" + str);
contextHolder.set(str);
}
/**
* 清理连接类型
*/
public static void clearDBType() {
contextHolder.remove();
}
}
DynamicDataSourceInterceptor.java
package com.imooc.o2o.dao.split;
import java.util.Locale;
import java.util.Properties;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.keygen.SelectKeyGenerator;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.support.TransactionSynchronizationManager;
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }),
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,
RowBounds.class, ResultHandler.class }) })
public class DynamicDataSourceInterceptor implements Interceptor {
private static Logger logger = LoggerFactory.getLogger(DynamicDataSourceInterceptor.class);
private static final String REGEX = ".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*";
@Override
public Object intercept(Invocation invocation) throws Throwable {
boolean synchronizationActive = TransactionSynchronizationManager.isActualTransactionActive();
Object[] objects = invocation.getArgs();
MappedStatement ms = (MappedStatement) objects[0];
String lookupKey = DynamicDataSourceHolder.DB_MASTER;
if (synchronizationActive != true) {
// 读方法
if (ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {
// selectKey 为自增id查询主键(SELECT LAST_INSERT_ID())方法,使用主库
if (ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) {
lookupKey = DynamicDataSourceHolder.DB_MASTER;
} else {
BoundSql boundSql = ms.getSqlSource().getBoundSql(objects[1]);
String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]", " ");
if (sql.matches(REGEX)) {
lookupKey = DynamicDataSourceHolder.DB_MASTER;
} else {
lookupKey = DynamicDataSourceHolder.DB_SLAVE;
}
}
}
} else {
lookupKey = DynamicDataSourceHolder.DB_MASTER;
}
logger.debug("设置方法[{}] use [{}] Strategy, SqlCommanType [{}]..", ms.getId(), lookupKey,
ms.getSqlCommandType().name());
DynamicDataSourceHolder.setDbType(lookupKey);
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties arg0) {
// TODO Auto-generated method stub
}
}
7、全局异常处理器
GlobalExceptionHandler.java
package com.imooc.o2o.web.handler;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import com.imooc.o2o.exceptions.ProductOperationException;
import com.imooc.o2o.exceptions.ShopOperationException;
@ControllerAdvice
public class GlobalExceptionHandler {
private final static Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Map<String, Object> handle(Exception e) {
Map<String, Object> modelMap = new HashMap<String, Object>();
modelMap.put("success", false);
if (e instanceof ShopOperationException) {
modelMap.put("errMsg", e.getMessage());
} else if (e instanceof ProductOperationException) {
modelMap.put("errMsg", e.getMessage());
} else {
LOG.error("系统出现异常", e.getMessage());
modelMap.put("errMsg", "未知错误,请联系工作人员进行解决");
}
return modelMap;
}
}
标签:拦截器,return,String,账号,微信,o2o,import,com,public 来源: https://blog.csdn.net/gongxifacai_believe/article/details/115562782