若依框架学习————持续更新
一、01-登录流程
1、用户发送请求进入到登录页面
//SysLoginController.java
@GetMapping("/login")
public String login(HttpServletRequest request, HttpServletResponse response)
{
// 如果是Ajax请求,返回Json字符串。
if (ServletUtils.isAjaxRequest(request))
{
return ServletUtils.renderString(response, "{\"code\":\"1\",\"msg\":\"未登录或登录超时。请重新登录\"}");
}
return "login";
}
- 对ajax和视图返回进行区分
//ServletUtils.java
/** * 是否是Ajax异步请求 * * @param request */
public static boolean isAjaxRequest(HttpServletRequest request)
{
String accept = request.getHeader("accept");
if (accept != null && accept.indexOf("application/json") != -1)
{
return true;
}
String xRequestedWith = request.getHeader("X-Requested-With");
if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1)
{
return true;
}
String uri = request.getRequestURI();
if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
{
return true;
}
String ajax = request.getParameter("__ajax");
if (StringUtils.inStringIgnoreCase(ajax, "json", "xml"))
{
return true;
}
return false;
}
-
同时页面发送一个验证码请求
// SysCaptchaController.java if ("math".equals(type)) { String capText = captchaProducerMath.createText(); capStr = capText.substring(0, capText.lastIndexOf("@")); code = capText.substring(capText.lastIndexOf("@") + 1); bi = captchaProducerMath.createImage(capStr); } else if ("char".equals(type)) { capStr = code = captchaProducer.createText(); bi = captchaProducer.createImage(capStr); } session.setAttribute(Constants.KAPTCHA_SESSION_KEY, code); out = response.getOutputStream(); ImageIO.write(bi, "jpg", out); out.flush();
-
若依使用的是谷歌提供的一个验证码生成器
com.google.code.kaptcha
,可以在配置类中配置验证码生成的参数,最后返回一个ImageIO
对象,controller
将图片对象通过流的形式写入到前端页面 -
验证码形式支持字符和数***算,数***算需要自定义一个文本生成器`
// 验证码文本生成器 properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator");
-
2、用户点击登录按钮
-
前端发送ajax请求
//login.js function login() { $.modal.loading($("#btnSubmit").data("loading")); var username = $.common.trim($("input[name='username']").val()); var password = $.common.trim($("input[name='password']").val()); var validateCode = $("input[name='validateCode']").val(); var rememberMe = $("input[name='rememberme']").is(':checked'); $.ajax({ type: "post", url: ctx + "login", data: { "username": username, "password": password, "validateCode": validateCode, //请求体中的验证码会在shiro验证码过滤器中进行验证 "rememberMe": rememberMe }, success: function(r) { //响应数据成功后,根据响应代码跳转到不同的页面 if (r.code == web_status.SUCCESS) { //登录成功,跳转到index页面 location.href = ctx + 'index'; } else { //登录失败 //关闭loading蒙层 $.modal.closeLoading(); //模拟点击一下刷新验证码按钮 $('.imgcode').click(); //清空验证码输入值 $(".code").val(""); //显示响应的错误消息 $.modal.msg(r.msg); } } }); }
-
发送POST请求到
/login
- 进行shiro权限验证
- 获取登录的token值
- 验证成功返回成功ajax数据,失败返回失败ajax数据
@PostMapping("/login")
@ResponseBody
public AjaxResult ajaxLogin(String username, String password, Boolean rememberMe)
{
UsernamePasswordToken token = new UsernamePasswordToken(username, password, rememberMe);
Subject subject = SecurityUtils.getSubject();
try
{
subject.login(token);
return success();
}
catch (AuthenticationException e)
{
String msg = "用户或密码错误";
if (StringUtils.isNotEmpty(e.getMessage()))
{
msg = e.getMessage();
}
return error(msg);
}
}
二、02-首页
-
发送get请求index视图
ModelMap和Model的用法类似
SysUser user = ShiroUtils.getSysUser();
获取当前登录的用户信息
//SysIndexController.java // 系统首页 @GetMapping("/index") public String index(ModelMap mmap) { // 取身份信息 SysUser user = ShiroUtils.getSysUser(); // 根据用户id取出菜单 List<SysMenu> menus = menuService.selectMenusByUser(user); mmap.put("menus", menus); mmap.put("user", user); mmap.put("sideTheme", configService.selectConfigByKey("sys.index.sideTheme")); mmap.put("skinName", configService.selectConfigByKey("sys.index.skinName")); mmap.put("ignoreFooter", configService.selectConfigByKey("sys.index.ignoreFooter")); mmap.put("copyrightYear", RuoYiConfig.getCopyrightYear()); mmap.put("demoEnabled", RuoYiConfig.isDemoEnabled()); mmap.put("isDefaultModifyPwd", initPasswordIsModify(user.getPwdUpdateDate())); mmap.put("isPasswordExpired", passwordIsExpiration(user.getPwdUpdateDate())); // 菜单导航显示风格 String menuStyle = configService.selectConfigByKey("sys.index.menuStyle"); // 移动端,默认使左侧导航菜单,否则取默认配置 String indexStyle = ServletUtils.checkAgentIsMobile(ServletUtils.getRequest().getHeader("User-Agent")) ? "index" : menuStyle; // 优先Cookie配置导航菜单 Cookie[] cookies = ServletUtils.getRequest().getCookies(); for (Cookie cookie : cookies) { if (StringUtils.isNotEmpty(cookie.getName()) && "nav-style".equalsIgnoreCase(cookie.getName())) { indexStyle = cookie.getValue(); break; } } String webIndex = "topnav".equalsIgnoreCase(indexStyle) ? "index-topnav" : "index"; return webIndex; }
-
从数据库查询到的菜单列表是没有树形结构的,进行了二次封装,最终返回树形结构的菜单到视图
//SysMenuServiceImpl.java /** * 根据用户查询菜单 * * @param user 用户信息 * @return 菜单列表 */ @Override public List<SysMenu> selectMenusByUser(SysUser user) { List<SysMenu> menus = new LinkedList<SysMenu>(); // 管理员显示所有菜单信息 if (user.isAdmin()) { menus = menuMapper.selectMenuNormalAll(); } else { menus = menuMapper.selectMenusByUserId(user.getUserId()); } return getChildPerms(menus, 0); } /** * 根据父节点的ID获取所有子节点 * * @param list 分类表 * @param parentId 传入的父节点ID * @return String */ public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) { List<SysMenu> returnList = new ArrayList<SysMenu>(); for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();) { SysMenu t = (SysMenu) iterator.next(); // 一、根据传入的某个父节点ID,遍历该父节点的所有子节点 if (t.getParentId() == parentId) { recursionFn(list, t); returnList.add(t); } } return returnList; } /** * 递归列表 * * @param list * @param t */ private void recursionFn(List<SysMenu> list, SysMenu t) { // 得到子节点列表 List<SysMenu> childList = getChildList(list, t); t.setChildren(childList); for (SysMenu tChild : childList) { if (hasChild(list, tChild)) { recursionFn(list, tChild); } } }