用户登录
在dao层下UserMapper里新增两个方法,检查用户名和验证登录
int checkUsername(String username);
User selectLogin(@Param("username") String username,@Param("password") String password);
然后去mappers下UserMapper.xml里写sql的实现,查询用select标签,id是在dao层下的方法名,resultType是返回值类型,parameterType是参数类型,标签里写sql语句,传入的参数用#{...}调用
在service层下新建一个UserService接口类,在子包impl包写新建UserServiceImpl实现类,加上Service注解声明这个类是service,在注入的对象上加上Autowired注解,自动注入,实现login和返回响应的内容
@Service("iUserService")
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper;
@Override
public ServerResponse login(String username, String password) {
int resultCount = userMapper.checkUsername(username);
if(resultCount == 0){
return ServerResponse.createByErrorMessage("用户名不存在");
}
//todo 密码登录md5
User user = userMapper.selectLogin(username,password);
if(user == null){
return ServerResponse.createByErrorMessage("密码错误");
}
user.setPassword(StringUtils.EMPTY);
return ServerResponse.createBySuccess("登录成功",user);
}
}
在controller层新建UserController,Controller注解声明为Controller。登录成功把用户信息放入session,登出从session删除。
@Controller
@RequestMapping("/user/")
public class UserController {
@Autowired
private IUserService iUserService;
/**
* 用户登录
* @param username
* @param password
* @param session
* @return
*/
@RequestMapping(value = "login.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse login(String username, String password, HttpSession session){
//service->mybatis->dao
ServerResponse response = iUserService.login(username,password);
if(response.isSuccess()){
session.setAttribute(Const.CURRENT_USER,response.getData());
}
return response;
}
@RequestMapping(value = "logout.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse logout(HttpSession session){
session.removeAttribute(Const.CURRENT_USER);
return ServerResponse.createBySuccess();
}
}
实现了登录和登出
用户注册
在UserServiceImpl里新建一个校验用户名和email是否存在的方法,传入两个参数,用type区别传入的是用户名还是email
isNoneBlank()和isNotEmpty()的区别
isNoneBlank(" ")返回的是false,isNotEmpty(" ")返回的是true
public ServerResponse checkValid(String str,String type){
if(StringUtils.isNoneBlank(type)){
if(Const.USERNAME.equals(type)){
int resultCount = userMapper.checkUsername(str);
if(resultCount > 0){
return ServerResponse.createByErrorMessage("用户名已存在");
}
}
if(Const.EMAIL.equals(type)){
int resultCount = userMapper.checkEmail(str);
if(resultCount > 0){
return ServerResponse.createByErrorMessage("email已存在");
}
}
}else{
return ServerResponse.createByErrorMessage("参数错误");
}
return ServerResponse.createBySuccessMessage("校验成功");
}
在UserMapper里配置方法名在UserMapper.xml里实现sql查询
int checkEmail(String email);
在写一个register方法调用验证成功后MD5进行加密后插入user到数据库
public ServerResponse register(User user){
ServerResponse validResponse = this.checkValid(user.getUsername(),Const.USERNAME);
if(!validResponse.isSuccess()){
return validResponse;
}
validResponse = this.checkValid(user.getEmail(),Const.EMAIL);
if(!validResponse.isSuccess()){
return validResponse;
}
user.setRole(Const.Role.ROLE_CUSTOMER);
//MD5加密
user.setPassword(MD5Util.MD5EncodeUtf8(user.getPassword()));
int resultCount = userMapper.insert(user);
if(resultCount==0){
return ServerResponse.createByErrorMessage("注册失败");
}
return ServerResponse.createBySuccessMessage("注册成功");
}
MD5工具类
对外有一个共有接口MD5EncodeUtf8(),传入字符串,加上properties文件里的盐值,传给私有方法MD5Encode()然后返回
public class MD5Util {
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
/**
* 返回大写MD5
*
* @param origin
* @param charsetname
* @return
*/
private static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString.toUpperCase();
}
public static String MD5EncodeUtf8(String origin) {
//origin = origin + PropertiesUtil.getProperty("password.salt", "");
return MD5Encode(origin, "utf-8");
}
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
}
在之前写的login方法里也要实现一下md5
....
//todo 密码登录md5
String md5password = MD5Util.MD5EncodeUtf8(password);
User user = userMapper.selectLogin(username,md5password);
if(user == null){
return ServerResponse.createByErrorMessage("密码错误");
}
user.setPassword(StringUtils.EMPTY);
return ServerResponse.createBySuccess("登录成功",user);
...
最后在controller里调用一下service的方法,注册接口就完成啦
....
@RequestMapping(value = "register.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse register(User user){
return iUserService.register(user);
}
@RequestMapping(value = "check_valid.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse checkValid(String str,String type){
return iUserService.checkValid(str,type);
}
}
密码找回
查找验证找回密码的问题和答案
在UserServiceImpl类里新增一个方法
public ServerResponse checkAnswer(String username,String question,String answer){
int resultCount = userMapper.checkAnswer(username, question, answer);
if(resultCount>0){
//答案及问题正确
String forgetToken = UUID.randomUUID().toString();
TokenCache.setKey("token_"+username,forgetToken);
return ServerResponse.createBySuccess(forgetToken);
}
return ServerResponse.createByErrorMessage("问题答案错误");
}
省略dao层的查询实现,resultCount>0时,即验证通过时,随机生成一个字符串作标识,然后用GUAVA cache把标识放进本地缓存,设置有效期等配置,新建一个TokenCache类
public class TokenCache {
private static Logger logger = LoggerFactory.getLogger(TokenCache.class);
private static LoadingCache localCache = CacheBuilder.newBuilder()
.initialCapacity(1000)
.maximumSize(10000)
.expireAfterAccess(12, TimeUnit.HOURS)
.build(new CacheLoader() {
//默认的数据加载实现,当调用get取值的时候,如果key没有值,就调用这个方法进行加载
@Override
public String load(String s) throws Exception {
return "null";
}
});
public static void setKey(String key,String value){
localCache.put(key,value);
}
public static String getKey(String key){
String value = null;
try {
value = localCache.get(key);
if("null".equals(value)){
return null;
}
return value;
}catch (Exception ex){
logger.error("localCache get error",ex);
}
return null;
}
}
logger是日志输出,loadingCache是Guava里的本地缓存,.newBuilder()之后.initialCapacity(1000)
初始化它,1000就是缓存的初始化容量,.maximumSize(10000)是最大容量,超过时使用LRU算法移除缓存项,.expireAfterAccess(12, TimeUnit.HOURS)设置了有限期,即12个小时,然后build。为了避免不必要的exception,把默认返回的null,改成字符串null(因为判断时,null.equals()会报错)
在UserServiceImpl类里新增一个方法,判断传进来的token和cache中的是否一致,不一致不可以更改密码,一致就执行dao层的update密码,
public ServerResponse forgetResetPassword(String username,String passwordNew,String forgetToken){
if(StringUtils.isBlank(forgetToken)){
return ServerResponse.createByErrorMessage("参数错误,token为空");
}
ServerResponse validResponse = this.checkValid(username,Const.USERNAME);
if(validResponse.isSuccess()){
//用户不存在
return ServerResponse.createByErrorMessage("用户不存在");
}
String token = TokenCache.getKey(TokenCache.TOKEN_PREFIX+username);
if(StringUtils.isBlank(token)){
return ServerResponse.createByErrorMessage("token无效");
}
if(StringUtils.equals(forgetToken,token)){
String md5Password = MD5Util.MD5EncodeUtf8(passwordNew);
int rowCount = userMapper.updatePasswordByUsername(username,md5Password);
if(rowCount>0){
return ServerResponse.createBySuccessMessage("密码修改成功");
}
}else{
return ServerResponse.createByErrorMessage("token错误");
}
return ServerResponse.createByErrorMessage("修改密码失败");
}
然后在controller调用service层
@RequestMapping(value = "forget_reset_password.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse forgetResetPassword(String username,String passwordNew,String forgetToken){
return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
}