Explorar o código

首页验证码功能修改

user5 %!s(int64=2) %!d(string=hai) anos
pai
achega
56e4ac6a26

+ 1 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/security/config/WebSecurityConfig.java

@@ -71,6 +71,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
                         "/sys/sysConfig/getConfig",
                         "/getAppFlowChart",
                         "/sys/getCode",
+                        "/sys/getLoginCodeNumber",
                         "/app/sys/getCode",
                         "/sys/casLogin").permitAll() // 允许请求无需认证
                 .antMatchers( HttpMethod.OPTIONS, "/**").permitAll()

+ 2 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/constant/CacheNames.java

@@ -39,5 +39,7 @@ public interface CacheNames {
 
      String USER_CACHE_TOKEN = "user:cache:token:";
 
+     String USER_CACHE_LOGIN_CODE = "user:cache:code:loginName"; //用户登录次数
+
 
 }

+ 52 - 2
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/controller/LoginController.java

@@ -22,6 +22,8 @@ import com.jeeplus.sys.model.LoginForm;
 import com.jeeplus.sys.service.SysConfigService;
 import com.jeeplus.sys.service.UserService;
 import com.jeeplus.sys.service.dto.UserDTO;
+import com.jeeplus.sys.utils.DictUtils;
+import com.jeeplus.sys.utils.StringUtils;
 import com.jeeplus.sys.utils.UserUtils;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -84,8 +86,26 @@ public class LoginController {
         String username = loginForm.getUsername ();
         String password = loginForm.getPassword ();
         String code = loginForm.getCode ();
-        if(!code.equals ( RedisUtils.getInstance ().get (CacheNames.SYS_CACHE_CODE, loginForm.getUuid ()))){
-            throw new AccountExpiredException ( ErrorConstants.LOGIN_ERROR_ERROR_VALIDATE_CODE );
+        Integer redisLoginNumber = (Integer) RedisUtils.getInstance ().get ( CacheNames.USER_CACHE_LOGIN_CODE + username );
+        if(null == redisLoginNumber){
+            redisLoginNumber = 0;
+        }else{
+            redisLoginNumber ++ ;
+        }
+        RedisUtils.getInstance().set(CacheNames.USER_CACHE_LOGIN_CODE + username , redisLoginNumber);
+        //给登录次数记录设置6小时的过期时间
+        RedisUtils.getInstance().expire(CacheNames.USER_CACHE_LOGIN_CODE + username , 21600);
+
+        String dictValue = DictUtils.getDictLabel("login_number", "login_verification_number", null);
+        //字典中限制显示次数
+        Integer loginNumber = 0;
+        if(StringUtils.isNotBlank(dictValue)) {
+            loginNumber = Integer.valueOf(dictValue);
+        }
+        if(redisLoginNumber > loginNumber){
+            if(!code.equals ( RedisUtils.getInstance ().get (CacheNames.SYS_CACHE_CODE, loginForm.getUuid ()))){
+                throw new AccountExpiredException ( ErrorConstants.LOGIN_ERROR_ERROR_VALIDATE_CODE );
+            }
         }
         SecurityUtils.login (username, password, authenticationManager  ); //登录操作spring security
 
@@ -103,6 +123,9 @@ public class LoginController {
         //更新登录信息
         updateUserLoginInfo ( responseUtil, userDTO , token);
 
+        //删除redis中登录次数的信息
+        RedisUtils.getInstance ().delete ( CacheNames.USER_CACHE_LOGIN_CODE + username );
+
         return responseUtil.ok ( );
     }
 
@@ -207,4 +230,31 @@ public class LoginController {
     }
 
 
+    /**
+     * 获取登录次数
+     * @throws
+     */
+    @ApiOperation ("获取登录次数")
+    @ApiLog("获取登录次数")
+    @GetMapping("/sys/getLoginCodeNumber")
+    public ResponseEntity getLoginCodeNumber(String userName){
+        //字典中限制显示次数
+        Integer loginNumber = 0;
+        //redis中记录登录次数
+        Object redisLoginNumber = RedisUtils.getInstance ().get ( CacheNames.USER_CACHE_LOGIN_CODE + userName );
+        if(null == redisLoginNumber){
+            redisLoginNumber = 0;
+        }
+        String dictValue = DictUtils.getDictLabel("login_number", "login_verification_number", null);
+        if(StringUtils.isNotBlank(dictValue)){
+            loginNumber = Integer.valueOf(dictValue);
+            if(loginNumber > 0){
+                loginNumber -- ;
+            }
+        }
+
+        return ResponseUtil.newInstance ().add ( "redisLoginNumber", redisLoginNumber ).add ( "loginNumber", loginNumber ).ok ();
+    }
+
+
 }

+ 151 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Encodes.java

@@ -0,0 +1,151 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.jeeplus.sys.utils;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.StringEscapeUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+
+/**
+ * 封装各种格式的编码解码工具类.
+ * 1.Commons-Codec的 hex/base64 编码
+ * 2.自制的base62 编码
+ * 3.Commons-Lang的xml/html escape
+ * 4.JDK提供的URLEncoder
+ * @author calvin
+ * @version 2013-01-15
+ */
+public class Encodes {
+
+	private static final String DEFAULT_URL_ENCODING = "UTF-8";
+	private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();
+
+	/**
+	 * Hex编码.
+	 */
+	public static String encodeHex(byte[] input) {
+		return new String(Hex.encodeHex(input));
+	}
+
+	/**
+	 * Hex解码.
+	 */
+	public static byte[] decodeHex(String input) {
+		try {
+			return Hex.decodeHex(input.toCharArray());
+		} catch (DecoderException e) {
+			throw Exceptions.unchecked(e);
+		}
+	}
+
+	/**
+	 * Base64编码.
+	 */
+	public static String encodeBase64(byte[] input) {
+		return new String(Base64.encodeBase64(input));
+	}
+
+	/**
+	 * Base64编码.
+	 */
+	public static String encodeBase64(String input) {
+		try {
+			return new String(Base64.encodeBase64(input.getBytes(DEFAULT_URL_ENCODING)));
+		} catch (UnsupportedEncodingException e) {
+			return "";
+		}
+	}
+
+//	/**
+//	 * Base64编码, URL安全(将Base64中的URL非法字符'+'和'/'转为'-'和'_', 见RFC3548).
+//	 */
+//	public static String encodeUrlSafeBase64(byte[] input) {
+//		return Base64.encodeBase64URLSafe(input);
+//	}
+
+	/**
+	 * Base64解码.
+	 */
+	public static byte[] decodeBase64(String input) {
+		return Base64.decodeBase64(input.getBytes());
+	}
+
+	/**
+	 * Base64解码.
+	 */
+	public static String decodeBase64String(String input) {
+		try {
+			return new String(Base64.decodeBase64(input.getBytes()), DEFAULT_URL_ENCODING);
+		} catch (UnsupportedEncodingException e) {
+			return "";
+		}
+	}
+
+	/**
+	 * Base62编码。
+	 */
+	public static String encodeBase62(byte[] input) {
+		char[] chars = new char[input.length];
+		for (int i = 0; i < input.length; i++) {
+			chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
+		}
+		return new String(chars);
+	}
+
+	/**
+	 * Html 转码.
+	 */
+	public static String escapeHtml(String html) {
+		return StringEscapeUtils.escapeHtml4(html);
+	}
+
+	/**
+	 * Html 解码.
+	 */
+	public static String unescapeHtml(String htmlEscaped) {
+		return StringEscapeUtils.unescapeHtml4(htmlEscaped);
+	}
+
+	/**
+	 * Xml 转码.
+	 */
+	public static String escapeXml(String xml) {
+		return StringEscapeUtils.escapeXml10(xml);
+	}
+
+	/**
+	 * Xml 解码.
+	 */
+	public static String unescapeXml(String xmlEscaped) {
+		return StringEscapeUtils.unescapeXml(xmlEscaped);
+	}
+
+	/**
+	 * URL 编码, Encode默认为UTF-8.
+	 */
+	public static String urlEncode(String part) {
+		try {
+			return URLEncoder.encode(part, DEFAULT_URL_ENCODING);
+		} catch (UnsupportedEncodingException e) {
+			throw Exceptions.unchecked(e);
+		}
+	}
+
+	/**
+	 * URL 解码, Encode默认为UTF-8. 
+	 */
+	public static String urlDecode(String part) {
+
+		try {
+			return URLDecoder.decode(part, DEFAULT_URL_ENCODING);
+		} catch (UnsupportedEncodingException e) {
+			throw Exceptions.unchecked(e);
+		}
+	}
+}

+ 71 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/Exceptions.java

@@ -0,0 +1,71 @@
+/**
+ * Copyright (c) 2005-2012 springside.org.cn
+ */
+package com.jeeplus.sys.utils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+/**
+ * 关于异常的工具类.
+ * @author calvin
+ * @version 2013-01-15
+ */
+public class Exceptions {
+
+	/**
+	 * 将CheckedException转换为UncheckedException.
+	 */
+	public static RuntimeException unchecked(Exception e) {
+		if (e instanceof RuntimeException) {
+			return (RuntimeException) e;
+		} else {
+			return new RuntimeException(e);
+		}
+	}
+
+	/**
+	 * 将ErrorStack转化为String.
+	 */
+	public static String getStackTraceAsString(Throwable e) {
+		if (e == null){
+			return "";
+		}
+		StringWriter stringWriter = new StringWriter();
+		e.printStackTrace(new PrintWriter(stringWriter));
+		return stringWriter.toString();
+	}
+
+	/**
+	 * 判断异常是否由某些底层的异常引起.
+	 */
+	public static boolean isCausedBy(Exception ex, Class<? extends Exception>... causeExceptionClasses) {
+		Throwable cause = ex.getCause();
+		while (cause != null) {
+			for (Class<? extends Exception> causeClass : causeExceptionClasses) {
+				if (causeClass.isInstance(cause)) {
+					return true;
+				}
+			}
+			cause = cause.getCause();
+		}
+		return false;
+	}
+
+	/**
+	 * 在request中获取异常类
+	 * @param request
+	 * @return 
+	 */
+	public static Throwable getThrowable(HttpServletRequest request){
+		Throwable ex = null;
+		if (request.getAttribute("exception") != null) {
+			ex = (Throwable) request.getAttribute("exception");
+		} else if (request.getAttribute("javax.servlet.error.exception") != null) {
+			ex = (Throwable) request.getAttribute("javax.servlet.error.exception");
+		}
+		return ex;
+	}
+	
+}

+ 86 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/SpringContextHolder.java

@@ -0,0 +1,86 @@
+/**
+ * Copyright &copy; 2015-2020 <a href="http://www.jeeplus.org/">JeePlus</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import org.apache.commons.lang3.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+/**
+ * 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候取出ApplicaitonContext.
+ * 
+ * @author Zaric
+ * @date 2013-5-29 下午1:25:40
+ */
+@Service
+@Lazy(false)
+public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
+
+	private static ApplicationContext applicationContext = null;
+
+	private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
+
+	/**
+	 * 取得存储在静态变量中的ApplicationContext.
+	 */
+	public static ApplicationContext getApplicationContext() {
+		assertContextInjected();
+		return applicationContext;
+	}
+
+	/**
+	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+	 */
+	@SuppressWarnings("unchecked")
+	public static <T> T getBean(String name) {
+		assertContextInjected();
+		return (T) applicationContext.getBean(name);
+	}
+
+	/**
+	 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
+	 */
+	public static <T> T getBean(Class<T> requiredType) {
+		assertContextInjected();
+		return applicationContext.getBean(requiredType);
+	}
+
+	/**
+	 * 清除SpringContextHolder中的ApplicationContext为Null.
+	 */
+	public static void clearHolder() {
+		if (logger.isDebugEnabled()){
+			logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);
+		}
+		applicationContext = null;
+	}
+
+	/**
+	 * 实现ApplicationContextAware接口, 注入Context到静态变量中.
+	 */
+	@Override
+	public void setApplicationContext(ApplicationContext applicationContext) {
+		SpringContextHolder.applicationContext = applicationContext;
+	}
+
+	/**
+	 * 实现DisposableBean接口, 在Context关闭时清理静态变量.
+	 */
+	@Override
+	public void destroy() throws Exception {
+		SpringContextHolder.clearHolder();
+	}
+
+	/**
+	 * 检查ApplicationContext不为空.
+	 */
+	private static void assertContextInjected() {
+		Validate.validState(applicationContext != null, "applicaitonContext属性未注入, 请在applicationContext.xml中定义SpringContextHolder.");
+	}
+}

+ 760 - 0
jeeplus-platform/jeeplus-admin/src/main/java/com/jeeplus/sys/utils/StringUtils.java

@@ -0,0 +1,760 @@
+/**
+ * Copyright &copy; 2013-2017 <a href="http://www.rhcncpa.com/">瑞华会计师事务所</a> All rights reserved.
+ */
+package com.jeeplus.sys.utils;
+
+import com.google.common.collect.Lists;
+import net.sf.json.JSONObject;
+import org.apache.commons.lang3.StringEscapeUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import org.springframework.web.servlet.LocaleResolver;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.UnsupportedEncodingException;
+import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 字符串工具类, 继承org.apache.commons.lang3.StringUtils类
+ * @author jeeplus
+ * @version 2013-05-22
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils {
+
+	private static final char SEPARATOR = '_';
+	private static final String CHARSET_NAME = "UTF-8";
+	private static final int DEF_DIV_SCALE = 10; //这个类不能实例化
+	public static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
+	public static SimpleDateFormat sdfs = new SimpleDateFormat("HHmm");
+
+	/**
+	 * 转换为字节数组
+	 * @param str
+	 * @return
+	 */
+	public static byte[] getBytes(String str){
+		if (str != null){
+			try {
+				return str.getBytes(CHARSET_NAME);
+			} catch (UnsupportedEncodingException e) {
+				return null;
+			}
+		}else{
+			return null;
+		}
+	}
+
+	/**
+	 * 转换为字节数组
+	 * @param bytes
+	 * @return
+	 */
+	public static String toString(byte[] bytes){
+		try {
+			return new String(bytes, CHARSET_NAME);
+		} catch (UnsupportedEncodingException e) {
+			return EMPTY;
+		}
+	}
+
+	/**
+	 * 是否包含字符串
+	 * @param str 验证字符串
+	 * @param strs 字符串组
+	 * @return 包含返回true
+	 */
+	public static boolean inString(String str, String... strs){
+		if (str != null){
+			for (String s : strs){
+				if (str.equals(trim(s))){
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+
+	/**
+	 * 替换掉HTML标签方法
+	 */
+	public static String replaceHtml(String html) {
+		if (isBlank(html)){
+			return "";
+		}
+		String regEx = "<.+?>";
+		Pattern p = Pattern.compile(regEx);
+		Matcher m = p.matcher(html);
+		String s = m.replaceAll("");
+		return s;
+	}
+
+	/**
+	 * 替换为手机识别的HTML,去掉样式及属性,保留回车。
+	 * @param html
+	 * @return
+	 */
+	public static String replaceMobileHtml(String html){
+		if (html == null){
+			return "";
+		}
+		return html.replaceAll("<([a-z]+?)\\s+?.*?>", "<$1>");
+	}
+
+	/**
+	 * 替换为手机识别的HTML,去掉样式及属性,保留回车。
+	 * @param txt
+	 * @return
+	 */
+	public static String toHtml(String txt){
+		if (txt == null){
+			return "";
+		}
+		return replace(replace(Encodes.escapeHtml(txt), "\n", "<br/>"), "\t", "&nbsp; &nbsp; ");
+	}
+
+	/**
+	 * 缩略字符串(不区分中英文字符)
+	 * @param str 目标字符串
+	 * @param length 截取长度
+	 * @return
+	 */
+	public static String abbr(String str, int length) {
+		if (str == null) {
+			return "";
+		}
+		try {
+			StringBuilder sb = new StringBuilder();
+			int currentLength = 0;
+			for (char c : replaceHtml(StringEscapeUtils.unescapeHtml4(str)).toCharArray()) {
+				currentLength += String.valueOf(c).getBytes("GBK").length;
+				if (currentLength <= length - 3) {
+					sb.append(c);
+				} else {
+					sb.append("...");
+					break;
+				}
+			}
+			return sb.toString();
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+		}
+		return "";
+	}
+
+	public static String abbr2(String param, int length) {
+		if (param == null) {
+			return "";
+		}
+		StringBuffer result = new StringBuffer();
+		int n = 0;
+		char temp;
+		boolean isCode = false; // 是不是HTML代码
+		boolean isHTML = false; // 是不是HTML特殊字符,如&nbsp;
+		for (int i = 0; i < param.length(); i++) {
+			temp = param.charAt(i);
+			if (temp == '<') {
+				isCode = true;
+			} else if (temp == '&') {
+				isHTML = true;
+			} else if (temp == '>' && isCode) {
+				n = n - 1;
+				isCode = false;
+			} else if (temp == ';' && isHTML) {
+				isHTML = false;
+			}
+			try {
+				if (!isCode && !isHTML) {
+					n += String.valueOf(temp).getBytes("GBK").length;
+				}
+			} catch (UnsupportedEncodingException e) {
+				e.printStackTrace();
+			}
+
+			if (n <= length - 3) {
+				result.append(temp);
+			} else {
+				result.append("...");
+				break;
+			}
+		}
+		// 取出截取字符串中的HTML标记
+		String temp_result = result.toString().replaceAll("(>)[^<>]*(<?)",
+				"$1$2");
+		// 去掉不需要结素标记的HTML标记
+		temp_result = temp_result
+				.replaceAll(
+						"</?(AREA|BASE|BASEFONT|BODY|BR|COL|COLGROUP|DD|DT|FRAME|HEAD|HR|HTML|IMG|INPUT|ISINDEX|LI|LINK|META|OPTION|P|PARAM|TBODY|TD|TFOOT|TH|THEAD|TR|area|base|basefont|body|br|col|colgroup|dd|dt|frame|head|hr|html|img|input|isindex|li|link|meta|option|p|param|tbody|td|tfoot|th|thead|tr)[^<>]*/?>",
+						"");
+		// 去掉成对的HTML标记
+		temp_result = temp_result.replaceAll("<([a-zA-Z]+)[^<>]*>(.*?)</\\1>",
+				"$2");
+		// 用正则表达式取出标记
+		Pattern p = Pattern.compile("<([a-zA-Z]+)[^<>]*>");
+		Matcher m = p.matcher(temp_result);
+		List<String> endHTML = Lists.newArrayList();
+		while (m.find()) {
+			endHTML.add(m.group(1));
+		}
+		// 补全不成对的HTML标记
+		for (int i = endHTML.size() - 1; i >= 0; i--) {
+			result.append("</");
+			result.append(endHTML.get(i));
+			result.append(">");
+		}
+		return result.toString();
+	}
+
+	/**
+	 * 转换为Double类型
+	 */
+	public static Double toDouble(Object val){
+		if (val == null){
+			return 0D;
+		}
+		try {
+			return Double.valueOf(trim(val.toString()));
+		} catch (Exception e) {
+			return 0D;
+		}
+	}
+
+	/**
+	 * 转换为Float类型
+	 */
+	public static Float toFloat(Object val){
+		return toDouble(val).floatValue();
+	}
+
+	/**
+	 * 转换为Long类型
+	 */
+	public static Long toLong(Object val){
+		return toDouble(val).longValue();
+	}
+
+	/**
+	 * 转换为Integer类型
+	 */
+	public static Integer toInteger(Object val){
+		return toLong(val).intValue();
+	}
+
+	/**
+	 * 获得i18n字符串
+	 */
+	public static String getMessage(String code, Object[] args) {
+		LocaleResolver localLocaleResolver = (LocaleResolver) SpringContextHolder.getBean(LocaleResolver.class);
+		HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+		Locale localLocale = localLocaleResolver.resolveLocale(request);
+		return SpringContextHolder.getApplicationContext().getMessage(code, args, localLocale);
+	}
+
+	/**
+	 * 获得用户远程地址
+	 */
+	public static String getRemoteAddr(HttpServletRequest request){
+		String remoteAddr = request.getHeader("X-Real-IP");
+		if (isNotBlank(remoteAddr)) {
+			remoteAddr = request.getHeader("X-Forwarded-For");
+		}else if (isNotBlank(remoteAddr)) {
+			remoteAddr = request.getHeader("Proxy-Client-IP");
+		}else if (isNotBlank(remoteAddr)) {
+			remoteAddr = request.getHeader("WL-Proxy-Client-IP");
+		}
+		return remoteAddr != null ? remoteAddr : request.getRemoteAddr();
+	}
+
+	/**
+	 * 驼峰命名法工具
+	 * @return
+	 * 		toCamelCase("hello_world") == "helloWorld"
+	 * 		toCapitalizeCamelCase("hello_world") == "HelloWorld"
+	 * 		toUnderScoreCase("helloWorld") = "hello_world"
+	 */
+	public static String toCamelCase(String s) {
+		if (s == null) {
+			return null;
+		}
+
+		s = s.toLowerCase();
+
+		StringBuilder sb = new StringBuilder(s.length());
+		boolean upperCase = false;
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+
+			if (c == SEPARATOR) {
+				upperCase = true;
+			} else if (upperCase) {
+				sb.append(Character.toUpperCase(c));
+				upperCase = false;
+			} else {
+				sb.append(c);
+			}
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * 驼峰命名法工具
+	 * @return
+	 * 		toCamelCase("hello_world") == "helloWorld"
+	 * 		toCapitalizeCamelCase("hello_world") == "HelloWorld"
+	 * 		toUnderScoreCase("helloWorld") = "hello_world"
+	 */
+	public static String toCapitalizeCamelCase(String s) {
+		if (s == null) {
+			return null;
+		}
+		s = toCamelCase(s);
+		return s.substring(0, 1).toUpperCase() + s.substring(1);
+	}
+
+	/**
+	 * 驼峰命名法工具
+	 * @return
+	 * 		toCamelCase("hello_world") == "helloWorld"
+	 * 		toCapitalizeCamelCase("hello_world") == "HelloWorld"
+	 * 		toUnderScoreCase("helloWorld") = "hello_world"
+	 */
+	public static String toUnderScoreCase(String s) {
+		if (s == null) {
+			return null;
+		}
+
+		StringBuilder sb = new StringBuilder();
+		boolean upperCase = false;
+		for (int i = 0; i < s.length(); i++) {
+			char c = s.charAt(i);
+
+			boolean nextUpperCase = true;
+
+			if (i < (s.length() - 1)) {
+				nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
+			}
+
+			if ((i > 0) && Character.isUpperCase(c)) {
+				if (!upperCase || !nextUpperCase) {
+					sb.append(SEPARATOR);
+				}
+				upperCase = true;
+			} else {
+				upperCase = false;
+			}
+
+			sb.append(Character.toLowerCase(c));
+		}
+
+		return sb.toString();
+	}
+
+	/**
+	 * 如果不为空,则设置值
+	 * @param target
+	 * @param source
+	 */
+	public static void setValueIfNotBlank(String target, String source) {
+		if (isNotBlank(source)){
+			target = source;
+		}
+	}
+
+	/**
+	 * 转换为JS获取对象值,生成三目运算返回结果
+	 * @param objectString 对象串
+	 *   例如:row.user.id
+	 *   返回:!row?'':!row.user?'':!row.user.id?'':row.user.id
+	 */
+	public static String jsGetVal(String objectString){
+		StringBuilder result = new StringBuilder();
+		StringBuilder val = new StringBuilder();
+		String[] vals = split(objectString, ".");
+		for (int i=0; i<vals.length; i++){
+			val.append("." + vals[i]);
+			result.append("!"+(val.substring(1))+"?'':");
+		}
+		result.append(val.substring(1));
+		return result.toString();
+	}
+
+
+
+	public static boolean isChinese(char c) {
+		Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
+		if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS
+				|| ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
+				|| ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
+				|| ub == Character.UnicodeBlock.GENERAL_PUNCTUATION) {
+			return true;
+		}
+		return false;
+	}
+
+	public static Map<String, String> StringToJson(String contentStr){
+		HashMap<String, String> requestMap = new HashMap<String, String>();
+
+
+		JSONObject jsonObject = JSONObject.fromObject(contentStr);//
+		Iterator<String> keys = jsonObject.keys();// 定义迭代器
+		String key = null;
+		String value = null;
+		while (keys.hasNext()) {
+			key = keys.next().toString();
+			value = jsonObject.get(key).toString();
+			requestMap.put(key.trim(), value.trim());
+		}
+		return requestMap;
+	}
+
+	/**
+	 * 根据键值对填充字符串,如("hello {name}",{name:"xiaoming"})
+	 * 输出:
+	 * @param content
+	 * @param map
+	 * @return
+	 */
+	public static String renderString(String content, Map<String, String> map){
+		Set<Map.Entry<String, String>> sets = map.entrySet();
+		for(Map.Entry<String, String> entry : sets) {
+			String regex = "\\{" + entry.getKey() + "\\}";
+			Pattern pattern = Pattern.compile(regex);
+			Matcher matcher = pattern.matcher(content);
+			content = matcher.replaceAll(entry.getValue());
+		}
+		return content;
+	}
+
+	/**
+	 * 提供精确的加法运算。
+	 * @param v1 被加数
+	 * @param v2 加数
+	 * @return 两个参数的和
+	 */
+	public static double add(double v1,double v2){
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.add(b2).doubleValue();
+	}
+	/**
+	 * 提供精确的减法运算。
+	 * @param v1 被减数
+	 * @param v2 减数
+	 * @return 两个参数的差
+	 */
+	public static double sub(double v1,double v2){
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.subtract(b2).doubleValue();
+	}
+	/**
+	 * 提供精确的乘法运算。
+	 * @param v1 被乘数
+	 * @param v2 乘数
+	 * @return 两个参数的积
+	 */
+	public static double mul(double v1,double v2){
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.multiply(b2).doubleValue();
+	}
+	/**
+	 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
+	 * 小数点以后10位,以后的数字四舍五入。
+	 * @param v1 被除数
+	 * @param v2 除数
+	 * @return 两个参数的商
+	 */
+	public static double div(double v1,double v2){
+		return div(v1,v2,DEF_DIV_SCALE);
+	}
+	/**
+	 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
+	 * 定精度,以后的数字四舍五入。
+	 * @param v1 被除数
+	 * @param v2 除数
+	 * @param scale 表示表示需要精确到小数点以后几位。
+	 * @return 两个参数的商
+	 */
+	public static double div(double v1,double v2,int scale){
+		if(scale<0){
+			throw new IllegalArgumentException(
+					"The scale must be a positive integer or zero");
+		}
+		BigDecimal b1 = new BigDecimal(Double.toString(v1));
+		BigDecimal b2 = new BigDecimal(Double.toString(v2));
+		return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
+	}
+	/**
+	 * 提供精确的小数位四舍五入处理。
+	 * @param v 需要四舍五入的数字
+	 * @param scale 小数点后保留几位
+	 * @return 四舍五入后的结果
+	 */
+	public static double round(double v,int scale){
+		if(scale<0){
+			throw new IllegalArgumentException("The scale must be a positive integer or zero");
+		}
+		BigDecimal b = new BigDecimal(Double.toString(v));
+		BigDecimal one = new BigDecimal("1");
+		return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
+	}
+
+	public static Map<String,String> getByDictMap(){
+		Map<String,String> map = new HashMap<>();
+		map.put("13","报销申请");
+		map.put("16","合同申请");
+		map.put("21","发票申请");
+		map.put("38","案例登记");
+		map.put("39","项目登记");
+		map.put("40","退票申请");
+		map.put("41","项目变更");
+		map.put("42","合同归档");
+		map.put("43","合同作废");
+		map.put("44","合同变更");
+		map.put("45","报告申请");
+		map.put("46","报告变更");
+		map.put("47","报告作废");
+		map.put("48","发票变更");
+		map.put("49","退票变更");
+		map.put("50","投标申请");
+		map.put("51","报告归档");
+		map.put("52","收入结算");
+		map.put("53","收入调整");
+		map.put("54","调整作废");
+		map.put("55","收文申请");
+		map.put("56","行政盖章");
+		map.put("57","采购合同");
+		map.put("58","日常事务");
+		map.put("59","借用申请");
+		map.put("60","归还借用");
+		map.put("61","采购申请");
+		map.put("62","发文申请");
+		map.put("63","报废申请");
+		map.put("64","领用申请");
+		map.put("66","转正申请");
+		map.put("67","劳动关系");
+		map.put("68","部门调转");
+		map.put("69","日常事务");
+		map.put("70","职级调整");
+		map.put("71","离职申请");
+		map.put("72","合同完成");
+		map.put("74","系统预警");
+		map.put("75","加入企业");
+		map.put("76","案例申请");
+		map.put("77","加班申请");
+		map.put("78","出差申请");
+		map.put("79","外勤申请");
+		map.put("80","请假申请");
+		map.put("81","销假申请");
+		map.put("82","续假申请");
+		map.put("83","补卡申请");
+		map.put("84","考勤审批");
+		return map;
+	}
+
+	public static String firstDay(String month,String day,String companyId) {
+		if(StringUtils.isBlank(month)) {
+			if (StringUtils.isBlank(day)) {
+				//获取上月第一天:
+				Calendar c = Calendar.getInstance();
+				c.add(Calendar.MONTH, -1);
+				c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
+				String first = format.format(c.getTime());
+				return first;
+			}else{
+				Calendar now = Calendar.getInstance();
+				int nowDay = now.get(Calendar.DAY_OF_MONTH);
+				now.set(Calendar.DAY_OF_MONTH, 0);
+				String last = format.format(now.getTime()).substring(8,10);
+				if (last.equals(day)){
+					return format.format(now.getTime()).substring(0,8)+"01";
+				}else {
+					if (nowDay < Integer.parseInt(day)) {
+						//获取上月第一天:
+						Calendar c = Calendar.getInstance();
+						c.add(Calendar.MONTH, -2);
+						c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
+						String first = format.format(c.getTime()).substring(0, 8) + (Integer.parseInt(day) < 10 ? "0" + Integer.parseInt(day) : day);
+						return first;
+					} else {
+						//获取上月第一天:
+						Calendar c = Calendar.getInstance();
+						c.add(Calendar.MONTH, -1);
+						c.set(Calendar.DAY_OF_MONTH, 1);//设置为1号,当前日期既为本月第一天
+						String first = format.format(c.getTime()).substring(0, 8) + (Integer.parseInt(day) < 10 ? "0" + Integer.parseInt(day) : day);
+						return first;
+					}
+				}
+			}
+		}else{
+			if (StringUtils.isBlank(day)) {
+				return month+"-01";
+			}else {
+				int m = Integer.parseInt(month.substring(5,7))-1;
+				if (m==1){
+					int year = Integer.parseInt(month.substring(0,4)) - 1;
+					return year+"-01-"+(Integer.parseInt(day)<10?"0"+day:day);
+				}else if(m>10){
+					return month.substring(0,5)+m+"-"+(Integer.parseInt(day)<10?"0"+Integer.parseInt(day):day);
+				}else{
+					return month.substring(0,5)+"0"+m+"-"+(Integer.parseInt(day)<10?"0"+Integer.parseInt(day):day);
+				}
+			}
+		}
+	}
+	public static String lastDay(String month,String day,String companyId) {
+		if(StringUtils.isBlank(month)) {
+			if (StringUtils.isBlank(day)) {
+				//获取上月最后一天
+				Calendar ca = Calendar.getInstance();
+				ca.set(Calendar.DAY_OF_MONTH, 0);
+				String last = format.format(ca.getTime());
+				return last;
+			}else{
+				Calendar now = Calendar.getInstance();
+				int nowDay = now.get(Calendar.DAY_OF_MONTH);
+				now.set(Calendar.DAY_OF_MONTH, 0);
+				String l = format.format(now.getTime()).substring(8,10);
+				if (l.equals(day)){
+					return format.format(now.getTime()).substring(0,8)+day;
+				}else {
+					if (nowDay < Integer.parseInt(day)) {
+						//获取上月最后一天
+
+						int days = Integer.parseInt(day) - 1;
+						if (days>0) {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, 0);
+							String last = format.format(ca.getTime()).substring(0, 8) + (days < 10 ? "0" + days : days);
+							return last;
+						}else {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, 1);
+							return format.format(ca.getTime());
+						}
+					} else {
+						//获取上月最后一天
+						int days = Integer.parseInt(day) - 1;
+						if (days>0) {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, +1);
+							String last = format.format(ca.getTime()).substring(0, 8) + (days < 10 ? "0" + days : days);
+							return last;
+						}else {
+							Calendar ca = Calendar.getInstance();
+							ca.set(Calendar.DAY_OF_MONTH, 0);
+							return format.format(ca.getTime());
+						}
+					}
+				}
+			}
+		}else {
+			if (StringUtils.isBlank(day)) {
+				//格式化日期
+				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+				Calendar cal = Calendar.getInstance();
+				//设置年份
+				cal.set( Integer.parseInt(month.substring(0,4)),(Integer.parseInt(month.substring(5,7))-1),1);
+				//设置月份
+				//获取某月最大天数
+				int lastDay = cal.getActualMaximum(Calendar.DATE);
+				//设置日历中月份的最大天数
+				cal.set(Calendar.DAY_OF_MONTH, lastDay);
+				return sdf.format(cal.getTime());
+			}else {
+				int days = Integer.parseInt(day)-1;
+				if (days>0){
+					return month+"-"+(days<10?"0"+days:days);
+				}else{
+					Calendar calendar = Calendar.getInstance();
+					Date date = null;
+					try {
+						date = format.parse(month+"-01");
+					} catch (ParseException e) {
+						e.printStackTrace();
+					}
+					calendar.setTime(date);
+					calendar.set(Calendar.DAY_OF_MONTH, -1);
+					int lastDay = calendar.getActualMaximum(Calendar.DATE);
+					//设置日历中月份的最大天数
+					calendar.set(Calendar.DAY_OF_MONTH, lastDay);
+					return format.format(calendar.getTime());
+				}
+			}
+		}
+	}
+	public static Boolean isWeek(String day) {
+		SimpleDateFormat sdfDay = new SimpleDateFormat("yyyy-MM-dd");
+		Date date= null;//取时间
+		try {
+			date = sdfDay.parse(day);
+			Calendar calendar = Calendar.getInstance();
+			calendar.setTime(date);
+			int week  =  calendar.get(Calendar.DAY_OF_WEEK)-1;
+			if (week==0 || week==6){
+				return true;
+			}else {
+				return false;
+			}
+		} catch (ParseException e) {
+			e.printStackTrace();
+		}
+		return false;
+	}
+
+	public static int lateEarlyTime(String cardType,Date start,Date end,Date now){
+		Integer nowh = Integer.parseInt(sdfs.format(new Date()).substring(0,2));
+		Integer nowm = Integer.parseInt(sdfs.format(new Date()).substring(2,4));
+		if (cardType.equals("1")){
+			Integer ruleh = Integer.parseInt(sdfs.format(start).substring(0,2));
+			Integer rulem = Integer.parseInt(sdfs.format(start).substring(2,4));
+			if (ruleh - nowh < 0 && rulem >= nowm){
+				return nowh - ruleh;
+			}else if(ruleh - nowh < 0 && rulem < nowm){
+				return nowh - ruleh + 1;
+			}else {
+				return 0;
+			}
+		}else {
+			Integer ruleh = Integer.parseInt(sdfs.format(end).substring(0,2));
+			Integer rulem = Integer.parseInt(sdfs.format(end).substring(2,4));
+			if (ruleh - nowh > 0 && rulem > nowm){
+				return ruleh - nowh + 1;
+			}else if(ruleh - nowh > 0 && rulem <= nowm){
+				return ruleh - nowh;
+			}else {
+				return 0;
+			}
+		}
+	}
+
+	public static Map<String,String> getMonth() {
+		//获取上月最后一天
+		Calendar ca = Calendar.getInstance();
+		String month = format.format(ca.getTime()).substring(0,7);
+		ca.set(Calendar.DAY_OF_MONTH, 0);
+		String oldMonth = format.format(ca.getTime()).substring(0,7);
+		Map<String,String> map = new HashMap<>();
+		map.put("1",month);
+		map.put("2",oldMonth);
+		return map;
+	}
+
+
+	/**
+	 * date转Str
+	 * @param currentTime
+	 * @return
+	 */
+	public static String getDateStr(Date currentTime) {
+		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
+		String dateString = formatter.format(currentTime);
+		return dateString;
+	}
+}

BIN=BIN
userfiles/1/程序附件/sys/user/images/login.png