登录功能的完善
我们使用分布式Session,也就是cookie+session的方式记录用户的信息。
所以我们需要创建一个生成cookie值和uuid的工具类。
cookie
public final class CookieUtil {
public static String getCookieValue(HttpServletRequest request, String
cookieName) {
return getCookieValue(request, cookieName, false);
}
public static String getCookieValue(HttpServletRequest request, String
cookieName, boolean isDecoder) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
if (isDecoder) {
retValue = URLDecoder.decode(cookieList[i].getValue(),
"UTF-8");
} else {
retValue = cookieList[i].getValue();
}
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
public static String getCookieValue(HttpServletRequest request, String
cookieName, String encodeString) {
Cookie[] cookieList = request.getCookies();
if (cookieList == null || cookieName == null) {
return null;
}
String retValue = null;
try {
for (int i = 0; i < cookieList.length; i++) {
if (cookieList[i].getName().equals(cookieName)) {
retValue = URLDecoder.decode(cookieList[i].getValue(),
encodeString);
break;
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return retValue;
}
public static void setCookie(HttpServletRequest request, HttpServletResponse
response, String cookieName,
String cookieValue) {
setCookie(request, response, cookieName, cookieValue, -1);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse
response, String cookieName,
String cookieValue, int cookieMaxage) {
setCookie(request, response, cookieName, cookieValue, cookieMaxage,
false);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse
response, String cookieName,
String cookieValue, boolean isEncode) {
setCookie(request, response, cookieName, cookieValue, -1, isEncode);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse
response, String cookieName,
String cookieValue, int cookieMaxage, boolean
isEncode) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage,
isEncode);
}
public static void setCookie(HttpServletRequest request, HttpServletResponse
response, String cookieName,
String cookieValue, int cookieMaxage, String
encodeString) {
doSetCookie(request, response, cookieName, cookieValue, cookieMaxage,
encodeString);
}
public static void deleteCookie(HttpServletRequest request,
HttpServletResponse response,
String cookieName) {
doSetCookie(request, response, cookieName, "", -1, false);
}
private static final void doSetCookie(HttpServletRequest request,
HttpServletResponse response,
String cookieName, String cookieValue,
int cookieMaxage, boolean isEncode) {
try {
if (cookieValue == null) {
cookieValue = "";
} else if (isEncode) {
cookieValue = URLEncoder.encode(cookieValue, "utf-8");
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0)
cookie.setMaxAge(cookieMaxage);
if (null != request) {// 设置域名的cookie
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
private static final void doSetCookie(HttpServletRequest request,
HttpServletResponse response,
String cookieName, String cookieValue,
int cookieMaxage, String encodeString) {
try {
if (cookieValue == null) {
cookieValue = "";
} else {
cookieValue = URLEncoder.encode(cookieValue, encodeString);
}
Cookie cookie = new Cookie(cookieName, cookieValue);
if (cookieMaxage > 0) {
cookie.setMaxAge(cookieMaxage);
}
if (null != request) {// 设置域名的cookie
String domainName = getDomainName(request);
System.out.println(domainName);
if (!"localhost".equals(domainName)) {
cookie.setDomain(domainName);
}
}
cookie.setPath("/");
response.addCookie(cookie);
} catch (Exception e) {
e.printStackTrace();
}
}
private static final String getDomainName(HttpServletRequest request) {
String domainName = null;
// 通过request对象获取访问的url地址
String serverName = request.getRequestURL().toString();
if (serverName == null || serverName.equals("")) {
domainName = "";
} else {
// 将url地下转换为小写
serverName = serverName.toLowerCase();
// 如果url地址是以http://开头 将http://截取
if (serverName.startsWith("http://")) {
serverName = serverName.substring(7);
}
int end = serverName.length();
// 判断url地址是否包含"/"
if (serverName.contains("/")) {
//得到第一个"/"出现的位置
end = serverName.indexOf("/");
}
// 截取
serverName = serverName.substring(0, end);
// 根据"."进行分割
final String[] domains = serverName.split("\.");
int len = domains.length;
if (len > 3) {
// www.xxx.com.cn
domainName = domains[len - 3] + "." + domains[len - 2] + "." +
domains[len - 1];
} else if (len <= 3 && len > 1) {
// xxx.com or xxx.cn
domainName = domains[len - 2] + "." + domains[len - 1];
} else {
domainName = serverName;
}
}
if (domainName != null && domainName.indexOf(":") > 0) {
String[] ary = domainName.split("\:");
domainName = ary[0];
}
return domainName;
}
UUID
import java.util.UUID;
public class UUIDUtil {
public static String uuid() {
return UUID.randomUUID().toString().replace("-", "");
}
}
这种工具类形式固定,所以直接用现有的模板就行。有了cookie和uuid之后我们需要在IUserService接口中定义login方法,用来验证用户登录信息,并且在impl中实现。
public interface IUserService extends IService{ //登录 PespBean login(HttpServletRequest request, HttpServletResponse response, LoginVO loginvo) throws IOException; }
impl
@Slf4j @Service public class UserServiceImpl extends ServiceImplimplements IUserService { @Resource private UserMapper userMapper; @Autowired private RedisTemplate redisTemplate; @Override public PespBean login(HttpServletRequest request, HttpServletResponse response, LoginVO loginvo) throws IOException { String mobile = loginvo.getMobile(); String passward = loginvo.getPassword(); // if(StringUtils.isEmpty(mobile)||StringUtils.isEmpty(passward)){ // return PespBean.error(RespBeanMnum.Error); // } // if(!ValidatorUtil.isMobile(mobile)){ // return PespBean.error(RespBeanMnum.MOBILE_ERROR); // } //获取用户信息 User user = userMapper.selectById(mobile); if(user == null) throw new GlobalException(RespBeanMnum.LOGIN_ERROR); //校验密码 if(!MD5Utils.formPassToDBPass(passward,user.getSlat()).equals(user.getPassward())){ throw new GlobalException(RespBeanMnum.LOGIN_ERROR); } //生成cookie String ticket = UUIDUtil.uuid(); log.info("id:{},ticket:{}",user,ticket); redisTemplate.opsForValue().set("user"+ticket,user); CookieUtil.setCookie(request,response,"userTicket",ticket); return PespBean.success(ticket); }
login方法中分别实现了验证手机号码格式的问题,账号密码匹配的问题以及是否为空的问题。
我们在VO类中从前端获取数据。
import com.hzc.seckill.validator.isMobile;
import lombok.Data;
import lombok.NonNull;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotNull;
//登录参数
@Data
public class LoginVO {
@NotNull
//自定义号码验证注解
@isMobile
private String mobile;
@NotNull
@Length(min = 32)
private String password;
}
respBean提供公共状态类型
//公共返回对象
@Data
//无参构造
@NoArgsConstructor
//全参构造
@AllArgsConstructor
public class PespBean {
private long code;
private String message;
private Object obj;
//成功返回结果
public static PespBean success(){
return new PespBean(RespBeanMnum.SUCCESS.getCode(), RespBeanMnum.SUCCESS.getMessage(), null);
}
//重载
public static PespBean success(Object obj){
return new PespBean(RespBeanMnum.SUCCESS.getCode(), RespBeanMnum.SUCCESS.getMessage(), obj);
}
//返回结果失败
public static PespBean error(RespBeanMnum respBeanMnum){
return new PespBean(respBeanMnum.getCode(), respBeanMnum.getMessage(), null);
}
}
//公共返回对象枚举
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.ToString;
@Getter
@ToString
@AllArgsConstructor
public enum RespBeanMnum {
SUCCESS(200,"SUCCESS"),
Error(500,"Server exception"),
//login in model
LOGIN_ERROR(500210,"suername eorror or passward error"),
MOBILE_ERROR(500211,"phone number error"),
SESSION_Error(500212,"the session is involid"),
BIND_ERROR(500213,"Parameter checksum error");
private final Integer code;
private final String message;
}
一切情景考虑完之后,成功登陆便可以转移到下一页面
@Controller
@RequestMapping("/login")
@Slf4j
public class LoginController {
@Autowired
private IUserService iuserservice;
//跳转登录页面
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/doLogin")
@ResponseBody
//登录
public PespBean doLogin(HttpServletRequest request, HttpServletResponse response, @Valid LoginVO loginvo) throws IOException {
log.info(loginvo.toString());
return iuserservice.login(request,response, loginvo);
}
}
登录页面呈现
!DOCTYPE html>
登录
goodsList.html
商品列表
在实现分布式Session的方法中我们采用后端集中存储,这样有利于水平扩展,并且安全,缺点就是增加复杂度,代码维护困难。



