前言:
在上一章 “SpringBoot 项目(若依脚手架)3”的基础上继续完成登录功能。
目录
一、编写Controller 层代码
二、重写 UserRealm 类中的 doGetAuthenticationInfo 方法(登录认证逻辑)
三、登录成功后,重定向到首页
四、本章大体流程图
思路整理:
①、前台页面传 什么样的数据?
②、验证码 如何处理?
1)前端传输的数据 (login.js 文件中的代码片段)
2) 验证码
验证码生成时,需要将验证码放入 session 中。之前我们编写 “SysCaptchaController” 类的时候,已经将 验证码存入session
过滤器拦截请求, 验证码禁用 或不是表单提交 允许访问; 验证码开启 并且是表单提交需要 校验验证码是否正确
CaptchaValidateFilter 类中 重写 isAccessAllowed 方法 @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest) request; // 验证码禁用 或不是表单提交 允许访问 if( captchaEnabled == false || !"post".equals(httpServletRequest.getMethod().toLowerCase())){ return true; } return validateResponse(httpServletRequest, httpServletRequest.getParameter(ShiroConstants.CURRENT_VALIDATECODE)); } public boolean validateResponse(HttpServletRequest httpServletRequest, String validatecode) { Object obj = ShiroUtils.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY); String code = String.valueOf(obj != null ? obj : ""); if(StringUtils.isEmpty(validatecode) || !validatecode.equalsIgnoreCase(code)){ return false; } return true; }CaptchaValidateFilter 类中用到 ShiroUtils 工具类中的 getSession 方法。这里顺便把 这个方法写一下
package com.ruoyi.framework.util; import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; /** * shiro 工具类 * * @author liangcy * @create 2019/10/14 - 11:32 */ public class ShiroUtils { public static Session getSession() { return SecurityUtils.getSubject().getSession(); } }3)编写 通用的返回数据类 AjaxResult
package com.ruoyi.common.core.domain; import com.ruoyi.common.utils.StringUtils; import java.util.HashMap; /** * 操作消息提醒 * * @author ruoyi */ public class AjaxResult extends HashMap<String, Object> { private static final long serialVersionUID = 1L; /** * 状态码 */ public static final String CODE_TAG = "code"; /** * 返回内容 */ public static final String MSG_TAG = "msg"; /** * 数据对象 */ public static final String DATA_TAG = "data"; /** * 状态类型 */ public enum Type { /** * 成功 */ SUCCESS(0), /** * 警告 */ WARN(301), /** * 错误 */ ERROR(500); private final int value; Type(int value) { this.value = value; } public int value() { return this.value; } } /** * 初始化一个新创建的 AjaxResult 对象,使其表示一个空消息。 */ public AjaxResult() { } /** * 初始化一个新创建的 AjaxResult 对象 * * @param type 状态类型 * @param msg 返回内容 */ public AjaxResult(Type type, String msg) { super.put(CODE_TAG, type.value); super.put(MSG_TAG, msg); } /** * 初始化一个新创建的 AjaxResult 对象 * * @param type 状态类型 * @param msg 返回内容 * @param data 数据对象 */ public AjaxResult(Type type, String msg, Object data) { super.put(CODE_TAG, type.value); super.put(MSG_TAG, msg); if (StringUtils.isNotNull(data)) { super.put(DATA_TAG, data); } } /** * 返回成功消息 * * @return 成功消息 */ public static AjaxResult success() { return AjaxResult.success("操作成功"); } /** * 返回成功数据 * * @return 成功消息 */ public static AjaxResult success(Object data) { return AjaxResult.success("操作成功", data); } /** * 返回成功消息 * * @param msg 返回内容 * @return 成功消息 */ public static AjaxResult success(String msg) { return AjaxResult.success(msg, null); } /** * 返回成功消息 * * @param msg 返回内容 * @param data 数据对象 * @return 成功消息 */ public static AjaxResult success(String msg, Object data) { return new AjaxResult(Type.SUCCESS, msg, data); } /** * 返回警告消息 * * @param msg 返回内容 * @return 警告消息 */ public static AjaxResult warn(String msg) { return AjaxResult.warn(msg, null); } /** * 返回警告消息 * * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 */ public static AjaxResult warn(String msg, Object data) { return new AjaxResult(Type.WARN, msg, data); } /** * 返回错误消息 * * @return */ public static AjaxResult error() { return AjaxResult.error("操作失败"); } /** * 返回错误消息 * * @param msg 返回内容 * @return 警告消息 */ public static AjaxResult error(String msg) { return AjaxResult.error(msg, null); } /** * 返回错误消息 * * @param msg 返回内容 * @param data 数据对象 * @return 警告消息 */ public static AjaxResult error(String msg, Object data) { return new AjaxResult(Type.ERROR, msg, data); } }4)编写 Controller 的基类 BaseController
BaseController 类中有以下几点功能:
①、获取 request、response、session 对象的方法
②、 响应返回结果、返回成功、返回失败 的方法
③、页面跳转 的方法
④、抽取出通用的 分页方法(后面1-2章会再弄)
⑤、处理 前端传来的日期,转换成 date(后面再弄)
package com.ruoyi.common.core.controller; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.AjaxResult.Type; import com.ruoyi.common.core.page.PageDomain; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.page.TableSupport; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.sql.SqlUtil; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.beans.PropertyEditorSupport; import java.util.Date; import java.util.List; /** * web层通用数据处理 * * @author ruoyi */ @Slf4j public class BaseController { /** * 获取request */ public HttpServletRequest getRequest() { return ServletUtils.getRequest(); } /** * 获取response */ public HttpServletResponse getResponse() { return ServletUtils.getResponse(); } /** * 获取session */ public HttpSession getSession() { return getRequest().getSession(); } /** * 响应返回结果 * * @param rows 影响行数 * @return 操作结果 */ protected AjaxResult toAjax(int rows) { return rows > 0 ? success() : error(); } /** * 响应返回结果 * * @param result 结果 * @return 操作结果 */ protected AjaxResult toAjax(boolean result) { return result ? success() : error(); } /** * 返回成功 */ public AjaxResult success() { return AjaxResult.success(); } /** * 返回失败消息 */ public AjaxResult error() { return AjaxResult.error(); } /** * 返回成功消息 */ public AjaxResult success(String message) { return AjaxResult.success(message); } /** * 返回失败消息 */ public AjaxResult error(String message) { return AjaxResult.error(message); } /** * 返回错误码消息 */ public AjaxResult error(Type type, String message) { return new AjaxResult(type, message); } /** * 页面跳转 */ public String redirect(String url) { return StringUtils.format("redirect:{}", url); } }补充:上面的基类中调用了 ServletUtils.getResponse()、StringUtils.format("redirect:{}", url) 工具类的方法,因此在这两个工具类中加入方法。
ServletUtils 类
/** * 获取response */ public static HttpServletResponse getResponse() { return getRequestAttributes().getResponse(); }StringUtils 类
/** * 格式化文本, {} 表示占位符<br> * 此方法只是简单将占位符 {} 按照顺序替换为参数<br> * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> * 例:<br> * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br> * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br> * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> * * @param template 文本模板,被替换的部分用 {} 表示 * @param params 参数值 * @return 格式化后的文本 */ public static String format(String template, Object... params) { if (isEmpty(params) || isEmpty(template)) { return template; } return StrFormatter.format(template, params); }StringUtils 类中又用到了 StrFormatter 类,顺便把这个类代码写一下
package com.ruoyi.common.core.text; import com.ruoyi.common.utils.StringUtils; /** * 字符串格式化 * * @author ruoyi */ public class StrFormatter { public static final String EMPTY_JSON = "{}"; public static final char C_BACKSLASH = '\\'; public static final char C_DELIM_START = '{'; public static final char C_DELIM_END = '}'; /** * 格式化字符串<br> * 此方法只是简单将占位符 {} 按照顺序替换为参数<br> * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> * 例:<br> * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br> * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br> * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> * * @param strPattern 字符串模板 * @param argArray 参数列表 * @return 结果 */ public static String format(final String strPattern, final Object... argArray) { if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) { return strPattern; } final int strPatternLength = strPattern.length(); // 初始化定义好的长度以获得更好的性能 StringBuilder sbuf = new StringBuilder(strPatternLength + 50); int handledPosition = 0; int delimIndex;// 占位符所在位置 for (int argIndex = 0; argIndex < argArray.length; argIndex++) { delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); if (delimIndex == -1) { if (handledPosition == 0) { return strPattern; } else { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 sbuf.append(strPattern, handledPosition, strPatternLength); return sbuf.toString(); } } else { if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) { if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) { // 转义符之前还有一个转义符,占位符依旧有效 sbuf.append(strPattern, handledPosition, delimIndex - 1); sbuf.append(Convert.utf8Str(argArray[argIndex])); handledPosition = delimIndex + 2; } else { // 占位符被转义 argIndex--; sbuf.append(strPattern, handledPosition, delimIndex - 1); sbuf.append(C_DELIM_START); handledPosition = delimIndex + 1; } } else { // 正常占位符 sbuf.append(strPattern, handledPosition, delimIndex); sbuf.append(Convert.utf8Str(argArray[argIndex])); handledPosition = delimIndex + 2; } } } // 加入最后一个占位符后所有的字符 sbuf.append(strPattern, handledPosition, strPattern.length()); return sbuf.toString(); } }StrFormatter 类中又用到了 Convert 转换器类
package com.ruoyi.common.core.text; import java.math.BigDecimal; import java.math.BigInteger; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.text.NumberFormat; import java.util.Set; import com.ruoyi.common.utils.StringUtils; /** * 类型转换器 * * @author ruoyi */ public class Convert { /** * 转换为字符串<br> * 如果给定的值为null,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static String toStr(Object value, String defaultValue) { if (null == value) { return defaultValue; } if (value instanceof String) { return (String) value; } return value.toString(); } /** * 转换为字符串<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static String toStr(Object value) { return toStr(value, null); } /** * 转换为字符<br> * 如果给定的值为null,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Character toChar(Object value, Character defaultValue) { if (null == value) { return defaultValue; } if (value instanceof Character) { return (Character) value; } final String valueStr = toStr(value, null); return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); } /** * 转换为字符<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Character toChar(Object value) { return toChar(value, null); } /** * 转换为byte<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Byte toByte(Object value, Byte defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Byte) { return (Byte) value; } if (value instanceof Number) { return ((Number) value).byteValue(); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return Byte.parseByte(valueStr); } catch (Exception e) { return defaultValue; } } /** * 转换为byte<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Byte toByte(Object value) { return toByte(value, null); } /** * 转换为Short<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Short toShort(Object value, Short defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Short) { return (Short) value; } if (value instanceof Number) { return ((Number) value).shortValue(); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return Short.parseShort(valueStr.trim()); } catch (Exception e) { return defaultValue; } } /** * 转换为Short<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Short toShort(Object value) { return toShort(value, null); } /** * 转换为Number<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Number toNumber(Object value, Number defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Number) { return (Number) value; } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return NumberFormat.getInstance().parse(valueStr); } catch (Exception e) { return defaultValue; } } /** * 转换为Number<br> * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Number toNumber(Object value) { return toNumber(value, null); } /** * 转换为int<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Integer toInt(Object value, Integer defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Integer) { return (Integer) value; } if (value instanceof Number) { return ((Number) value).intValue(); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return Integer.parseInt(valueStr.trim()); } catch (Exception e) { return defaultValue; } } /** * 转换为int<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Integer toInt(Object value) { return toInt(value, null); } /** * 转换为Integer数组<br> * * @param str 被转换的值 * @return 结果 */ public static Integer[] toIntArray(String str) { return toIntArray(",", str); } /** * 转换为Long数组<br> * * @param str 被转换的值 * @return 结果 */ public static Long[] toLongArray(String str) { return toLongArray(",", str); } /** * 转换为Integer数组<br> * * @param split 分隔符 * @param split 被转换的值 * @return 结果 */ public static Integer[] toIntArray(String split, String str) { if (StringUtils.isEmpty(str)) { return new Integer[]{}; } String[] arr = str.split(split); final Integer[] ints = new Integer[arr.length]; for (int i = 0; i < arr.length; i++) { final Integer v = toInt(arr[i], 0); ints[i] = v; } return ints; } /** * 转换为Long数组<br> * * @param split 分隔符 * @param str 被转换的值 * @return 结果 */ public static Long[] toLongArray(String split, String str) { if (StringUtils.isEmpty(str)) { return new Long[]{}; } String[] arr = str.split(split); final Long[] longs = new Long[arr.length]; for (int i = 0; i < arr.length; i++) { final Long v = toLong(arr[i], null); longs[i] = v; } return longs; } /** * 转换为String数组<br> * * @param str 被转换的值 * @return 结果 */ public static String[] toStrArray(String str) { return toStrArray(",", str); } /** * 转换为String数组<br> * * @param split 分隔符 * @param split 被转换的值 * @return 结果 */ public static String[] toStrArray(String split, String str) { return str.split(split); } /** * 转换为long<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Long toLong(Object value, Long defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Long) { return (Long) value; } if (value instanceof Number) { return ((Number) value).longValue(); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { // 支持科学计数法 return new BigDecimal(valueStr.trim()).longValue(); } catch (Exception e) { return defaultValue; } } /** * 转换为long<br> * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Long toLong(Object value) { return toLong(value, null); } /** * 转换为double<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Double toDouble(Object value, Double defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Double) { return (Double) value; } if (value instanceof Number) { return ((Number) value).doubleValue(); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { // 支持科学计数法 return new BigDecimal(valueStr.trim()).doubleValue(); } catch (Exception e) { return defaultValue; } } /** * 转换为double<br> * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Double toDouble(Object value) { return toDouble(value, null); } /** * 转换为Float<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Float toFloat(Object value, Float defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Float) { return (Float) value; } if (value instanceof Number) { return ((Number) value).floatValue(); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return Float.parseFloat(valueStr.trim()); } catch (Exception e) { return defaultValue; } } /** * 转换为Float<br> * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Float toFloat(Object value) { return toFloat(value, null); } /** * 转换为boolean<br> * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static Boolean toBool(Object value, Boolean defaultValue) { if (value == null) { return defaultValue; } if (value instanceof Boolean) { return (Boolean) value; } String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } valueStr = valueStr.trim().toLowerCase(); switch (valueStr) { case "true": return true; case "false": return false; case "yes": return true; case "ok": return true; case "no": return false; case "1": return true; case "0": return false; default: return defaultValue; } } /** * 转换为boolean<br> * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static Boolean toBool(Object value) { return toBool(value, null); } /** * 转换为Enum对象<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * * @param clazz Enum的Class * @param value 值 * @param defaultValue 默认值 * @return Enum */ public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) { if (value == null) { return defaultValue; } if (clazz.isAssignableFrom(value.getClass())) { @SuppressWarnings("unchecked") E myE = (E) value; return myE; } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return Enum.valueOf(clazz, valueStr); } catch (Exception e) { return defaultValue; } } /** * 转换为Enum对象<br> * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> * * @param clazz Enum的Class * @param value 值 * @return Enum */ public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) { return toEnum(clazz, value, null); } /** * 转换为BigInteger<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static BigInteger toBigInteger(Object value, BigInteger defaultValue) { if (value == null) { return defaultValue; } if (value instanceof BigInteger) { return (BigInteger) value; } if (value instanceof Long) { return BigInteger.valueOf((Long) value); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return new BigInteger(valueStr); } catch (Exception e) { return defaultValue; } } /** * 转换为BigInteger<br> * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static BigInteger toBigInteger(Object value) { return toBigInteger(value, null); } /** * 转换为BigDecimal<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @param defaultValue 转换错误时的默认值 * @return 结果 */ public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) { if (value == null) { return defaultValue; } if (value instanceof BigDecimal) { return (BigDecimal) value; } if (value instanceof Long) { return new BigDecimal((Long) value); } if (value instanceof Double) { return new BigDecimal((Double) value); } if (value instanceof Integer) { return new BigDecimal((Integer) value); } final String valueStr = toStr(value, null); if (StringUtils.isEmpty(valueStr)) { return defaultValue; } try { return new BigDecimal(valueStr); } catch (Exception e) { return defaultValue; } } /** * 转换为BigDecimal<br> * 如果给定的值为空,或者转换失败,返回默认值<br> * 转换失败不会报错 * * @param value 被转换的值 * @return 结果 */ public static BigDecimal toBigDecimal(Object value) { return toBigDecimal(value, null); } /** * 将对象转为字符串<br> * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 * * @param obj 对象 * @return 字符串 */ public static String utf8Str(Object obj) { return str(obj, CharsetKit.CHARSET_UTF_8); } /** * 将对象转为字符串<br> * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 * * @param obj 对象 * @param charsetName 字符集 * @return 字符串 */ public static String str(Object obj, String charsetName) { return str(obj, Charset.forName(charsetName)); } /** * 将对象转为字符串<br> * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 * * @param obj 对象 * @param charset 字符集 * @return 字符串 */ public static String str(Object obj, Charset charset) { if (null == obj) { return null; } if (obj instanceof String) { return (String) obj; } else if (obj instanceof byte[] || obj instanceof Byte[]) { return str((Byte[]) obj, charset); } else if (obj instanceof ByteBuffer) { return str((ByteBuffer) obj, charset); } return obj.toString(); } /** * 将byte数组转为字符串 * * @param bytes byte数组 * @param charset 字符集 * @return 字符串 */ public static String str(byte[] bytes, String charset) { return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); } /** * 解码字节码 * * @param data 字符串 * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 * @return 解码后的字符串 */ public static String str(byte[] data, Charset charset) { if (data == null) { return null; } if (null == charset) { return new String(data); } return new String(data, charset); } /** * 将编码的byteBuffer数据转换为字符串 * * @param data 数据 * @param charset 字符集,如果为空使用当前系统字符集 * @return 字符串 */ public static String str(ByteBuffer data, String charset) { if (data == null) { return null; } return str(data, Charset.forName(charset)); } /** * 将编码的byteBuffer数据转换为字符串 * * @param data 数据 * @param charset 字符集,如果为空使用当前系统字符集 * @return 字符串 */ public static String str(ByteBuffer data, Charset charset) { if (null == charset) { charset = Charset.defaultCharset(); } return charset.decode(data).toString(); } // ----------------------------------------------------------------------- 全角半角转换 /** * 半角转全角 * * @param input String. * @return 全角字符串. */ public static String toSBC(String input) { return toSBC(input, null); } /** * 半角转全角 * * @param input String * @param notConvertSet 不替换的字符集合 * @return 全角字符串. */ public static String toSBC(String input, Set<Character> notConvertSet) { char c[] = input.toCharArray(); for (int i = 0; i < c.length; i++) { if (null != notConvertSet && notConvertSet.contains(c[i])) { // 跳过不替换的字符 continue; } if (c[i] == ' ') { c[i] = '\u3000'; } else if (c[i] < '\177') { c[i] = (char) (c[i] + 65248); } } return new String(c); } /** * 全角转半角 * * @param input String. * @return 半角字符串 */ public static String toDBC(String input) { return toDBC(input, null); } /** * 替换全角为半角 * * @param text 文本 * @param notConvertSet 不替换的字符集合 * @return 替换后的字符 */ public static String toDBC(String text, Set<Character> notConvertSet) { char c[] = text.toCharArray(); for (int i = 0; i < c.length; i++) { if (null != notConvertSet && notConvertSet.contains(c[i])) { // 跳过不替换的字符 continue; } if (c[i] == '\u3000') { c[i] = ' '; } else if (c[i] > '\uFF00' && c[i] < '\uFF5F') { c[i] = (char) (c[i] - 65248); } } String returnString = new String(c); return returnString; } /** * 数字金额大写转换 先写个完整的然后将如零拾替换成零 * * @param n 数字 * @return 中文大写数字 */ public static String digitUppercase(double n) { String[] fraction = {"角", "分"}; String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}}; String head = n < 0 ? "负" : ""; n = Math.abs(n); String s = ""; for (int i = 0; i < fraction.length; i++) { s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); } if (s.length() < 1) { s = "整"; } int integerPart = (int) Math.floor(n); for (int i = 0; i < unit[0].length && integerPart > 0; i++) { String p = ""; for (int j = 0; j < unit[1].length && n > 0; j++) { p = digit[integerPart % 10] + unit[1][j] + p; integerPart = integerPart / 10; } s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; } return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); } }Convert 转换器类 又用到了 CharsetKit 字符集工具类
package com.ruoyi.common.core.text; import com.ruoyi.common.utils.StringUtils; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; /** * 字符集工具类 * * @author ruoyi */ public class CharsetKit { /** * ISO-8859-1 */ public static final String ISO_8859_1 = "ISO-8859-1"; /** * UTF-8 */ public static final String UTF_8 = "UTF-8"; /** * GBK */ public static final String GBK = "GBK"; /** * ISO-8859-1 */ public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); /** * UTF-8 */ public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); /** * GBK */ public static final Charset CHARSET_GBK = Charset.forName(GBK); /** * 转换为Charset对象 * * @param charset 字符集,为空则返回默认字符集 * @return Charset */ public static Charset charset(String charset) { return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); } /** * 转换字符串的字符集编码 * * @param source 字符串 * @param srcCharset 源字符集,默认ISO-8859-1 * @param destCharset 目标字符集,默认UTF-8 * @return 转换后的字符集 */ public static String convert(String source, String srcCharset, String destCharset) { return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); } /** * 转换字符串的字符集编码 * * @param source 字符串 * @param srcCharset 源字符集,默认ISO-8859-1 * @param destCharset 目标字符集,默认UTF-8 * @return 转换后的字符集 */ public static String convert(String source, Charset srcCharset, Charset destCharset) { if (null == srcCharset) { srcCharset = StandardCharsets.ISO_8859_1; } if (null == destCharset) { srcCharset = StandardCharsets.UTF_8; } if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) { return source; } return new String(source.getBytes(srcCharset), destCharset); } /** * @return 系统字符集编码 */ public static String systemCharset() { return Charset.defaultCharset().name(); } }补充:写这个 BaseController 类用到的工具方法还是比较多的,常有一个工具类调用另一个工具类,这些工具类没什么好讲的,直接粘贴就完了。
5)编写Controller代码
①、SysLoginController 继承 BaseController 类
@Controller public class SysLoginController extends BaseController {②、在 SysLoginController 类中,添加 ajaxLogin 方法,处理登录请求
@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 AjaxResult.error(msg); } }①、注入 SysLoginService
②、重写 doGetAuthenticationInfo 方法
package com.ruoyi.framework.shiro.realm; import com.ruoyi.common.exception.user.*; import com.ruoyi.framework.shiro.service.SysLoginService; import com.ruoyi.system.domain.SysUser; import lombok.extern.slf4j.Slf4j; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import javax.annotation.Resource; /** * * @author liangcy * @create 2019/10/9 - 14:20 */ @Slf4j public class UserRealm extends AuthorizingRealm { @Resource private SysLoginService loginService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("授权代码...."); return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("登录认证代码。。。。"); UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); String password = ""; if(upToken.getPassword() != null){ password = new String(upToken.getPassword()); } SysUser user = null; try { user = loginService.login(username, password); } catch (CaptchaException e){ throw new AuthenticationException(e.getMessage(), e); } catch (UserNotExistsException e){ throw new UnknownAccountException(e.getMessage(), e); } catch (UserPasswordNotMatchException e){ throw new IncorrectCredentialsException(e.getMessage(), e); } catch (UserBlockedException e){ throw new LockedAccountException(e.getMessage(), e); } catch (RoleBlockedException e){ throw new LockedAccountException(e.getMessage(), e); } catch(Exception e) { log.info("对用户[" + username + "]进行登录验证..验证未通过{}", e.getMessage()); throw new AuthenticationException(e.getMessage(), e); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } }首先,我们来看一下 login.js 中对于登录成功的处理逻辑
1)如果 r.code ==0 ,那么表示登录成功,页面会重定向到 /index 页面,考虑到此章节篇幅过长,因此 /index的请求到下一章再写。
2)我们重启服务,然后输入正确的账号密码,会发现页面地址发生重定向,如下图所示,本章内容也完成了
