1. 主要技术
SpringBoot+Mybatis+spring+mysql+layui
2. 目前的项目图
3. 目前的实现功能
(1)登录功能
登录的逻辑主要是下判断是否存在该用户,如果存在该用户就比较密码是否正确,如果正确登录成功。
主要是三层:
controller:接受请求、返回结果
接受前端的参数
调用service层的登录方法
返回给前端
@PostMapping("login") @ResponseBody public ResultInfo userLogin(String userName,String userPwd){ ResultInfo resultInfo=new ResultInfo(); UserModel userModel=userService.userLogin(userName,userPwd); resultInfo.setResult(userModel); return resultInfo; }
service层:业务逻辑层(非空判断、条件判断)
判空操作
调用dao层通过用户名查询对象
@Resource private UserMapper userMapper; /*** * login成功后返回一个userModel * 1.检查用户、密码是否为空 * 2.通过用户名查询user * 3.检查密码是否正确 * 4.生成一个usermodel返回给controller * @param userName * @param userPwd * @return */ @Override public UserModel userLogin(String userName,String userPwd){ checkLoginParams(userName,userPwd); User user=userMapper.queryByUserByName(userName); AssertUtil.isTrue(user==null,"用户姓名不存在"); checkUserPwd(userPwd,user.getUserPassword()); return buildUserInfo(user); } private UserModel buildUserInfo(User user) { UserModel userModel=new UserModel(); userModel.setUserIdStr(UserIDBase64.encoderUserID(user.getId())); userModel.setUserName(user.getUserName()); userModel.setTrueName(user.getTrueName()); return userModel; } private void checkUserPwd(String userPwd, String userPassword) { userPwd= Md5Util.encode(userPwd); AssertUtil.isTrue(!userPwd.equals(userPassword),"用户密码不正确"); } /*** * 检查用户名、密码是否为空 * @param userName * @param userPwd */ private void checkLoginParams(String userName, String userPwd) { AssertUtil.isTrue(StringUtils.isBlank(userName),"用户姓名不能为空"); AssertUtil.isTrue(StringUtils.isBlank(userPwd),"用户密码不能为空"); }
其中AssertUtil为工具类:
public class AssertUtil { public static void isTrue(Boolean flag,String msg){ if(flag){ throw new ParamsException(msg); } } }
dao层:与数据层相关
(2)修改密码
思路:
controller层:
接受前端传到的三个参数(旧密码、新密码、确认的新密码)
利用request获取到cookie中的主键ID
调用service层的修改密码方法
返回给前端参数
@ResponseBody @PostMapping("updatePassword") public ResultInfo updatePassword(HttpServletRequest request,String oldPassword, String newPassword, String repeatPassword){ ResultInfo resultInfo=new ResultInfo(); System.out.println(oldPassword); try{ Integer userId= LoginUserUtil.releaseUserIdFromCookie(request); userService.updatePassword(userId,oldPassword,newPassword,repeatPassword); }catch (ParamsException p){ resultInfo.setCode(p.getCode()); resultInfo.setMsg(p.getMsg()); p.printStackTrace(); }catch (Exception e){ resultInfo.setCode(500); resultInfo.setMsg("登录失败"); e.printStackTrace(); } return resultInfo; } @RequestMapping("toPasswordPage") public String toPasswordPage(){ return "user/password"; }
service层:
接受controller的四个参数
通过id查询用户user
参数校验:
user是否为空
旧密码是否为空,旧密码是否错误
新密码是否为空,新密码是否与旧密码相同
确认新密码是否为空,确认信密码是否与新密码相同
对新密码进行加密
调用dao层进行密码更新
执行更新判断受影响行数,判断是否更新成功
@Override @Transactional(propagation = Propagation.REQUIRED) public void updatePassword(Integer userId,String oldPwd,String newPwd,String repeatPwd ){ User user=userMapper.selectByPrimaryKey(userId); AssertUtil.isTrue(user==null,"待更新记录不存在"); System.out.println(oldPwd); checkPasswordParams(user,oldPwd,newPwd,repeatPwd); user.setUserPassword(Md5Util.encode(newPwd)); userMapper.updateByPrimaryKeySelective(user); AssertUtil.isTrue(userMapper.updateByPrimaryKeySelective(user)<1,"修改密码失败"); } private void checkPasswordParams(User user,String oldPwd, String newPwd, String repeatPwd) { AssertUtil.isTrue(StringUtils.isBlank(oldPwd),"旧密码不能为空"); AssertUtil.isTrue(user.getUserPassword().equals(Md5Util.encode(oldPwd)),"原始密码不正确"); AssertUtil.isTrue(StringUtils.isBlank(newPwd),"新密码不能为空"); AssertUtil.isTrue(newPwd.equals(oldPwd),"新密码不能与旧密码相同"); AssertUtil.isTrue(StringUtils.isBlank(repeatPwd),"确认新密码不能为空"); AssertUtil.isTrue(!repeatPwd.equals(newPwd),"确认新密码与新密码不一致"); }
dao层:
数据库的update操作
(3)记住我、退出功能
记住我和退出主要都是通过cookies进行实现,主要在前端js就可以实现
// 如果点击记住我 设置cookie 过期时间7天 if($("input[type='checkbox']").is(':checked')){ // 写入cookie 7天 $.cookie("userId",result.userIdStr, { expires: 7 }); $.cookie("userName",result.userName, { expires: 7 }); $.cookie("trueName",result.trueName, { expires: 7 }); }
$(".login-out").click(function () { layer.confirm('是否登出当前用户?', {icon: 3, title:'提示'}, function(index){ $.removeCookie("userId",{path:"/"}) $.removeCookie("userName",{path:"/"}) $.removeCookie("trueName",{path:"/"}) window.parent.location.href = ctx + "/index"; layer.close(index); });
(4)拦截器
当用户未登录的时候不能直接访问到主页面main
拦截器:
/** * 非法访问拦截 */ public class NoLoginInterceptor extends HandlerInterceptorAdapter { @Resource private UserServiceImpl userService; /** * 判断用户是否是登录状态 * 获取Cookie对象,解析用户ID的值 * 如果用户ID不为空,且在数据库中存在对应的用户记录,表示请求合法 * 否则,请求不合法,进行拦截,重定向到登录页面 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 获取Cookie中的用户ID Integer userId = LoginUserUtil.releaseUserIdFromCookie(request); // 判断用户ID是否不为空,且数据库中存在对应的用户记录 if (null == userId || null == userService.selectByPrimaryKey(userId)) { // 抛出未登录异常 throw new UnLoginException(); } return true; } }
配置拦截器:
@Configuration public class MvcConfig extends WebMvcConfigurerAdapter { @Bean public NoLoginInterceptor noLoginInterceptor() { return new NoLoginInterceptor(); } /** * 添加拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { // 需要一个实现HandlerInterceptor接口的拦截器实例,这里使用的是 NoLoginInterceptor registry.addInterceptor(noLoginInterceptor()) // 用于设置拦截器的过滤路径规则 .addPathPatterns("/**") // 用于设置不需要拦截的过滤规则 .excludePathPatterns("/index","/user/login","/css/**","/images/**","/js/**","/lib/**"); } }
4. 异常
(1)参数异常
/** * 自定义参数异常 */ public class ParamsException extends RuntimeException { private Integer code=300; private String msg="参数异常!"; public ParamsException() { super("参数异常!"); } public ParamsException(String msg) { super(msg); this.msg = msg; } public ParamsException(Integer code) { super("参数异常!"); this.code = code; } public ParamsException(Integer code, String msg) { super(msg); this.code = code; this.msg = msg; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
(2)全局异常处理
/* 全局异常处理 @ResponseBody响应内容为json数据,反之则是响应内容为页面 */ @Component public class GlobalExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object handler, Exception e) { ModelAndView mv = new ModelAndView(); //默认返回 mv.setViewName("error"); mv.addObject("code",500); mv.addObject("msg","系统出现异常,请稍后重试"); //如果用户未登录,抛出未登录异常,则无需进行后续判断 if(e instanceof UnLoginException){ mv.setViewName("un_login"); mv.addObject("msg","用户未登录!"); mv.addObject("ctx",httpServletRequest.getContextPath()); return mv; } //判断是否符合请求格式 if (handler instanceof HandlerMethod){ HandlerMethod hm = (HandlerMethod) handler; ResponseBody responseBody = hm.getMethod().getDeclaredAnnotation(ResponseBody.class); if(responseBody == null){ //如果为视图 //判断是否为参数异常 if(e instanceof ParamsException){ ParamsException PE = (ParamsException) e; mv.addObject("msg",PE.getMsg()); mv.addObject("code",PE.getCode()); } //是否为认证异常 else if(e instanceof AuthException){ AuthException ae = (AuthException) e; mv.addObject("msg",ae.getMsg()); mv.addObject("code",ae.getCode()); } return mv; } else{ //如果为json格式 ResultInfo resultInfo = new ResultInfo(); //默认数据 resultInfo.setCode(500); resultInfo.setMsg("系统出现错误,稍后重试"); //参数错误 if(e instanceof ParamsException){ ParamsException PE = (ParamsException) e; resultInfo.setCode(PE.getCode()); resultInfo.setMsg(PE.getMsg()); } //如果是认证错误 else if(e instanceof AuthException){ AuthException ae = (AuthException) e; resultInfo.setCode(ae.getCode()); resultInfo.setMsg(ae.getMsg()); } //返回json格式的错误信息 httpServletResponse.setContentType("application/json;charset=utf-8"); httpServletResponse.setCharacterEncoding("utf-8"); //使用流操作返回 PrintWriter pw = null; try { pw=httpServletResponse.getWriter(); pw.write(JSON.toJSONString(resultInfo)); pw.flush(); } catch (Exception ex) { ex.printStackTrace(); }finally { if(null != pw){ pw.close(); } } return null; } } else { //返回默认数据 return mv; } } }
(3)未登录异常
public class UnLoginException extends RuntimeException { private Integer code=300; private String msg="用户未登录!"; public UnLoginException() { super("用户未登录!"); } public UnLoginException(String msg) { super(msg); this.msg = msg; } public UnLoginException(Integer code) { super("用户未登录!"); this.code = code; } public UnLoginException(Integer code, String msg) { super(msg); this.code = code; this.msg = msg; } public Integer getCode() { return code; } public void setCode(Integer code) { this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }