用戶登錄
在dao層下UserMapper里新增兩個(gè)方法谈山,檢查用戶名和驗(yàn)證登錄
int checkUsername(String username);
User selectLogin(@Param("username") String username,@Param("password") String password);
然后去mappers下UserMapper.xml里寫sql的實(shí)現(xiàn)纹蝴,查詢用select標(biāo)簽,id是在dao層下的方法名,resultType是返回值類型抄淑,parameterType是參數(shù)類型猛遍,標(biāo)簽里寫sql語句馋记,傳入的參數(shù)用#{...}調(diào)用
<select id="checkUsername" resultType="int" parameterType="string">
select count(1) from mmall_user
where username = #{username}
</select>
<select id="selectLogin" resultMap="BaseResultMap" parameterType="map">
select
<include refid="Base_Column_List" />
from mmall_user
where username = #{username}
and password = #{password}
</select>
在service層下新建一個(gè)UserService接口類,在子包impl包寫新建UserServiceImpl實(shí)現(xiàn)類懊烤,加上Service注解聲明這個(gè)類是service梯醒,在注入的對(duì)象上加上Autowired注解,自動(dòng)注入腌紧,實(shí)現(xiàn)login和返回響應(yīng)的內(nèi)容
@Service("iUserService")
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper;
@Override
public ServerResponse<User> 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("密碼錯(cuò)誤");
}
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<User> login(String username, String password, HttpSession session){
//service->mybatis->dao
ServerResponse<User> 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<String> logout(HttpSession session){
session.removeAttribute(Const.CURRENT_USER);
return ServerResponse.createBySuccess();
}
}
實(shí)現(xiàn)了登錄和登出
用戶注冊(cè)
在UserServiceImpl里新建一個(gè)校驗(yàn)用戶名和email是否存在的方法代箭,傳入兩個(gè)參數(shù),用type區(qū)別傳入的是用戶名還是email
isNoneBlank()和isNotEmpty()的區(qū)別
isNoneBlank(" ")返回的是false涕刚,isNotEmpty(" ")返回的是true
public ServerResponse<String> 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("參數(shù)錯(cuò)誤");
}
return ServerResponse.createBySuccessMessage("校驗(yàn)成功");
}
在UserMapper里配置方法名在UserMapper.xml里實(shí)現(xiàn)sql查詢
int checkEmail(String email);
<select id="checkEmail" resultType="int" parameterType="string">
select count(1) from mmall_user
where email = #{email}
</select>
在寫一個(gè)register方法調(diào)用驗(yàn)證成功后MD5進(jìn)行加密后插入user到數(shù)據(jù)庫
public ServerResponse<String> 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("注冊(cè)失敗");
}
return ServerResponse.createBySuccessMessage("注冊(cè)成功");
}
MD5工具類
對(duì)外有一個(gè)共有接口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方法里也要實(shí)現(xiàn)一下md5
....
//todo 密碼登錄md5
String md5password = MD5Util.MD5EncodeUtf8(password);
User user = userMapper.selectLogin(username,md5password);
if(user == null){
return ServerResponse.createByErrorMessage("密碼錯(cuò)誤");
}
user.setPassword(StringUtils.EMPTY);
return ServerResponse.createBySuccess("登錄成功",user);
...
最后在controller里調(diào)用一下service的方法杜漠,注冊(cè)接口就完成啦
....
@RequestMapping(value = "register.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse<String> register(User user){
return iUserService.register(user);
}
@RequestMapping(value = "check_valid.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse<String> checkValid(String str,String type){
return iUserService.checkValid(str,type);
}
}
密碼找回
查找驗(yàn)證找回密碼的問題和答案
在UserServiceImpl類里新增一個(gè)方法
public ServerResponse<String> 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("問題答案錯(cuò)誤");
}
省略dao層的查詢實(shí)現(xiàn)极景,resultCount>0時(shí),即驗(yàn)證通過時(shí)驾茴,隨機(jī)生成一個(gè)字符串作標(biāo)識(shí)盼樟,然后用GUAVA cache把標(biāo)識(shí)放進(jìn)本地緩存,設(shè)置有效期等配置锈至,新建一個(gè)TokenCache類
public class TokenCache {
private static Logger logger = LoggerFactory.getLogger(TokenCache.class);
private static LoadingCache<String,String> localCache = CacheBuilder.newBuilder()
.initialCapacity(1000)
.maximumSize(10000)
.expireAfterAccess(12, TimeUnit.HOURS)
.build(new CacheLoader<String, String>() {
//默認(rèn)的數(shù)據(jù)加載實(shí)現(xiàn)晨缴,當(dāng)調(diào)用get取值的時(shí)候,如果key沒有值峡捡,就調(diào)用這個(gè)方法進(jìn)行加載
@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)是最大容量,超過時(shí)使用LRU算法移除緩存項(xiàng)砚婆,.expireAfterAccess(12, TimeUnit.HOURS)設(shè)置了有限期械拍,即12個(gè)小時(shí),然后build装盯。為了避免不必要的exception殊者,把默認(rèn)返回的null,改成字符串null(因?yàn)榕袛鄷r(shí)验夯,null.equals()會(huì)報(bào)錯(cuò))
在UserServiceImpl類里新增一個(gè)方法猖吴,判斷傳進(jìn)來的token和cache中的是否一致,不一致不可以更改密碼挥转,一致就執(zhí)行dao層的update密碼海蔽,
public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
if(StringUtils.isBlank(forgetToken)){
return ServerResponse.createByErrorMessage("參數(shù)錯(cuò)誤,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錯(cuò)誤");
}
return ServerResponse.createByErrorMessage("修改密碼失敗");
}
然后在controller調(diào)用service層
@RequestMapping(value = "forget_reset_password.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse<String> forgetResetPassword(String username,String passwordNew,String forgetToken){
return iUserService.forgetResetPassword(username, passwordNew, forgetToken);
}