├── .classpath ├── .gitattributes ├── .gitignore ├── .project ├── .settings ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs ├── org.eclipse.m2e.core.prefs └── org.eclipse.wst.common.project.facet.core.xml ├── README.md ├── libs └── javabase64-1.3.1.jar ├── pom.xml └── src └── main ├── java └── com │ └── scienjus │ ├── Application.java │ ├── authorization │ ├── annotation │ │ ├── Authorization.java │ │ └── CurrentUser.java │ ├── interceptor │ │ └── AuthorizationInterceptor.java │ ├── manager │ │ ├── SAASTokenManager.java │ │ ├── TokenManager.java │ │ └── impl │ │ │ └── RedisTokenManager.java │ ├── model │ │ └── TokenModel.java │ └── resolvers │ │ └── CurrentUserMethodArgumentResolver.java │ ├── config │ ├── Constants.java │ ├── MvcConfig.java │ ├── ResultStatus.java │ └── SwaggerConfig.java │ ├── controller │ └── TokenController.java │ ├── domain │ └── User.java │ ├── model │ ├── AccessToken.java │ └── ResultModel.java │ ├── repository │ └── UserRepository.java │ └── utils │ ├── Base64Utils.java │ ├── DateFormatUtil.java │ ├── MD5Utils.java │ └── RSAUtils.java └── resources ├── application.properties ├── init.sql └── public ├── css ├── print.css ├── reset.css ├── screen.css ├── style.css └── typography.css ├── fonts ├── droid-sans-v6-latin-700.eot ├── droid-sans-v6-latin-700.svg ├── droid-sans-v6-latin-700.ttf ├── droid-sans-v6-latin-700.woff ├── droid-sans-v6-latin-700.woff2 ├── droid-sans-v6-latin-regular.eot ├── droid-sans-v6-latin-regular.svg ├── droid-sans-v6-latin-regular.ttf ├── droid-sans-v6-latin-regular.woff └── droid-sans-v6-latin-regular.woff2 ├── images ├── explorer_icons.png ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── logo_small.png ├── pet_store_api.png ├── throbber.gif └── wordnik_api.png ├── index.html ├── lib ├── backbone-min.js ├── handlebars-2.0.0.js ├── highlight.7.3.pack.js ├── jquery-1.8.0.min.js ├── jquery.ba-bbq.min.js ├── jquery.slideto.min.js ├── jquery.wiggle.min.js ├── marked.js ├── swagger-oauth.js ├── underscore-min.js └── underscore-min.map ├── o2c.html ├── swagger-ui.js └── swagger-ui.min.js /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | 19 | *.html linguist-language=Java 20 | *.js linguist-language=Java 21 | *.css linguist-language=Java 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | /target/ 45 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | spring-restful-authorization 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.wst.jsdt.core.javascriptValidator 10 | 11 | 12 | 13 | 14 | org.eclipse.jdt.core.javabuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.wst.common.project.facet.core.builder 20 | 21 | 22 | 23 | 24 | org.eclipse.wst.validation.validationbuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | org.springframework.ide.eclipse.core.springbuilder 35 | 36 | 37 | 38 | 39 | 40 | org.springframework.ide.eclipse.core.springnature 41 | org.eclipse.jem.workbench.JavaEMFNature 42 | org.eclipse.wst.common.modulecore.ModuleCoreNature 43 | org.eclipse.jdt.core.javanature 44 | org.eclipse.m2e.core.maven2Nature 45 | org.eclipse.wst.common.project.facet.core.nature 46 | org.eclipse.wst.jsdt.core.jsNature 47 | 48 | 49 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding//src/main/resources=UTF-8 4 | encoding//src/main/resources/application.properties=UTF-8 5 | encoding/=UTF-8 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.8 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.wst.common.project.facet.core.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ###简介 2 | 3 | 主要展示后端token机制,怎样生成?怎样加密?单点登录,跨域等多种问题 4 | 5 | ###演示方式 6 | 7 | 1. 下载该项目并修改application.properties文件,将MySQL和Redis的信息修改为自己的配置 8 | 2. 打开init.sql文件,将其中的sql语句在MySQL中运行 9 | 3. 通过mvn spring-boot:run启动项目,如果日志输出Started Application in 8.112 seconds (JVM running for 14.491)说明启动成功 10 | 4. 浏览器打开localhost:8080,可以看到swagger-ui的主页 11 | 5. 演示登录:在该页面打开POST tokens/,在username项输入admin、password项输入password,点击Try it out!,查看返回结果得到userId和token 12 | 6. 演示退出登录:在该页面打开DELETE tokens/,在authorization中填写用userId和token以"_"拼接得到的字符串,点击Try it out!,如果返回码为200则成功。重复一次操作,返回码将变为401 13 | 14 | ###可能会遇到的问题: 15 | 16 | **java.lang.ClassNotFoundException: org.jboss.jandex.IndexView** 17 | 18 | 原因是缺少`org.jboss:jandex:1.1.0Final`依赖,可能需要您手动在`pom.xml`中依赖中添加以下内容: 19 | 20 | ``` 21 | 22 | org.jboss 23 | jandex 24 | 1.1.0.Final 25 | 26 | ``` 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /libs/javabase64-1.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/libs/javabase64-1.3.1.jar -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.scienjus 6 | spring-restful-authorization 7 | 1.0-SNAPSHOT 8 | jar 9 | 10 | spring-restful-authorization-demo 11 | http://maven.apache.org 12 | 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.2.5.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-web 34 | 35 | 36 | 37 | org.springframework.boot 38 | spring-boot-starter-data-jpa 39 | 40 | 41 | mysql 42 | mysql-connector-java 43 | 5.1.38 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-redis 49 | 1.3.5.RELEASE 50 | 51 | 52 | 53 | com.mangofactory 54 | swagger-springmvc 55 | 1.0.2 56 | 57 | 58 | 59 | 60 | ${project.artifactId} 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/Application.java: -------------------------------------------------------------------------------- 1 | package com.scienjus; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | /** 8 | * Spring-Boot启动类 9 | * @author ScienJus 10 | * @date 2015/7/31. 11 | */ 12 | @SpringBootApplication 13 | @EnableAutoConfiguration 14 | public class Application { 15 | 16 | public static void main(String[] args) { 17 | SpringApplication.run(Application.class); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/annotation/Authorization.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 在Controller的方法上使用此注解,该方法在映射时会检查用户是否登录,未登录返回401错误 10 | * @see com.scienjus.authorization.interceptor.AuthorizationInterceptor 11 | * @author ScienJus 12 | * @date 2015/7/31. 13 | */ 14 | @Target(ElementType.METHOD) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface Authorization { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/annotation/CurrentUser.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | 8 | /** 9 | * 在Controller的方法参数中使用此注解,该方法在映射时会注入当前登录的User对象 10 | * @see com.scienjus.authorization.resolvers.CurrentUserMethodArgumentResolver 11 | * @author ScienJus 12 | * @date 2015/7/31. 13 | */ 14 | @Target(ElementType.PARAMETER) 15 | @Retention(RetentionPolicy.RUNTIME) 16 | public @interface CurrentUser { 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/interceptor/AuthorizationInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.interceptor; 2 | 3 | import com.scienjus.authorization.annotation.Authorization; 4 | import com.scienjus.authorization.model.TokenModel; 5 | import com.scienjus.authorization.manager.TokenManager; 6 | import com.scienjus.config.Constants; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.stereotype.Component; 9 | import org.springframework.web.method.HandlerMethod; 10 | import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; 11 | 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | import java.lang.reflect.Method; 15 | 16 | /** 17 | * 自定义拦截器,判断此次请求是否有权限 18 | * @see com.scienjus.authorization.annotation.Authorization 19 | * @author ScienJus 20 | * @date 2015/7/30. 21 | */ 22 | @Component 23 | public class AuthorizationInterceptor extends HandlerInterceptorAdapter { 24 | 25 | @Autowired 26 | private TokenManager manager; 27 | 28 | public boolean preHandle(HttpServletRequest request, 29 | HttpServletResponse response, Object handler) throws Exception { 30 | //如果不是映射到方法直接通过 31 | if (!(handler instanceof HandlerMethod)) { 32 | return true; 33 | } 34 | HandlerMethod handlerMethod = (HandlerMethod) handler; 35 | Method method = handlerMethod.getMethod(); 36 | //从header中得到token 37 | String authorization = request.getHeader(Constants.AUTHORIZATION); 38 | //验证token 39 | TokenModel model = manager.getToken(authorization); 40 | if (manager.checkToken(model)) { 41 | //如果token验证成功,将token对应的用户id存在request中,便于之后注入 42 | request.setAttribute(Constants.CURRENT_USER_ID, model.getUserId()); 43 | return true; 44 | } 45 | //如果验证token失败,并且方法注明了Authorization,返回401错误 46 | if (method.getAnnotation(Authorization.class) != null) { 47 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); 48 | return false; 49 | } 50 | return true; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/manager/SAASTokenManager.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.manager; 2 | import java.io.UnsupportedEncodingException; 3 | import java.sql.Timestamp; 4 | import java.util.Date; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import javassist.bytecode.Mnemonic; 9 | 10 | import org.springframework.util.Base64Utils; 11 | 12 | import com.scienjus.model.AccessToken; 13 | import com.scienjus.utils.RSAUtils; 14 | 15 | 16 | /** 17 | * SAAS Token管理工具 18 | * 19 | * @packge com.wlyd.wmscloud.util.SAASTokenManager 20 | * @date 2016年5月6日 上午10:20:01 21 | * @author pengjunlin 22 | * @comment 23 | * @update 24 | */ 25 | public class SAASTokenManager { 26 | 27 | 28 | /** 29 | * Token存储对象,保持5000个并发容量(K-useraccount@corCode,V-token) 30 | */ 31 | public static Map map = new ConcurrentHashMap( 32 | 5000); 33 | 34 | /** 35 | * 获取用户Token 36 | * 37 | * @MethodName: getToken 38 | * @Description: 39 | * @param key 40 | * @return 41 | * @throws 42 | */ 43 | public static AccessToken getToken(String key) { 44 | if (map.containsKey(key)) { 45 | return (AccessToken) map.get(key); 46 | } 47 | return null; 48 | } 49 | 50 | /** 51 | * 添加用户token 52 | * 53 | * @MethodName: putToken 54 | * @Description: 55 | * @param key 56 | * useraccount@corCode 57 | * @param accessToken 58 | * @throws 59 | */ 60 | public static void putToken(String key, AccessToken accessToken) { 61 | map.put(key, accessToken); 62 | } 63 | 64 | /** 65 | * 移除token 66 | * 67 | * @MethodName: removeToken 68 | * @Description: 69 | * @param key 70 | * useraccount@corCode 71 | * @throws 72 | */ 73 | public static void removeToken(String key) { 74 | if (map.containsKey(key)) { 75 | map.remove(key); 76 | } 77 | } 78 | 79 | /** 80 | * 验证Token是否过期 81 | * 82 | * @MethodName: isVlidateToken 83 | * @Description: 84 | * @param key 85 | * useraccount@corCode 86 | * @return 87 | * @throws 88 | */ 89 | public static boolean isVlidateToken(String key) { 90 | if (map.containsKey(key)) { 91 | AccessToken accessToken = (AccessToken) map.get(key); 92 | long currentTimestamp = new Date().getTime(); 93 | // 有效时间两小时 94 | if (accessToken.getLongTime() - currentTimestamp > 2 * 3600 * 1000) { 95 | return false; 96 | } 97 | return true; 98 | } 99 | return false; 100 | } 101 | 102 | /** 103 | * 更新Token 104 | * 105 | * @MethodName: reputToken 106 | * @Description: 107 | * @param key 108 | * useraccount@corCode 109 | * @param accessToken 110 | * @return 111 | * @throws 112 | */ 113 | public static void reputToken(String key, AccessToken accessToken) { 114 | if (map.containsKey(key)) { 115 | putToken(key, accessToken); 116 | } 117 | } 118 | 119 | /** 120 | * 更新Token 121 | * 122 | * @MethodName: reputToken 123 | * @Description: 124 | * @param key 125 | * useraccount@corCode 126 | * @param tokenStr 127 | * @return 128 | * @throws 129 | */ 130 | public static void reputToken(String key, String tokenStr) { 131 | if (map.containsKey(key)) { 132 | AccessToken accessToken = new AccessToken(); 133 | accessToken.setToken(tokenStr); 134 | accessToken.setTimestamp(new Timestamp(new Date().getTime())); 135 | putToken(key, accessToken); 136 | } 137 | } 138 | 139 | /** 140 | * 是否包含用户token 141 | * @MethodName: iscontainKey 142 | * @Description: 143 | * @param key 144 | * useraccount@corCode 145 | * @return 146 | * @throws 147 | */ 148 | public static boolean iscontainKey(String key){ 149 | return map.containsKey(key); 150 | } 151 | 152 | /** 153 | * 生成RSA加密 Token 154 | * 155 | * @MethodName: generateToken 156 | * @Description: 157 | * @param platformCode 158 | * @param tenantCode 159 | * @return 160 | * @throws 161 | */ 162 | public static String generateToken(String publicKey,String platformCode,String tenantCode){ 163 | String str=platformCode+tenantCode+new Date().getTime(); 164 | try { 165 | byte [] bytes= RSAUtils.encryptByPublicKey(str.getBytes(),publicKey); 166 | return new String( bytes,"utf-8"); 167 | } catch (Exception e) { 168 | e.printStackTrace(); 169 | } 170 | return null; 171 | } 172 | 173 | /** 174 | * @throws Exception 175 | * 测试函数入口 176 | * 177 | * @MethodName: main 178 | * @Description: 179 | * @param args 180 | * @throws 181 | */ 182 | public static void main(String[] args) throws Exception { 183 | Map key= RSAUtils.genKeyPair(); 184 | String publicKey= RSAUtils.getPublicKey(key); 185 | String privateKey= RSAUtils.getPrivateKey(key); 186 | System.out.println("公钥:"+publicKey); 187 | System.out.println("私钥:"+privateKey); 188 | byte [] miwen=RSAUtils.encryptByPublicKey("13266699268".getBytes(), publicKey); 189 | System.out.println(new String(miwen)); 190 | System.out.println(Base64Utils.encodeToString(miwen)); 191 | String str="hoV41eWKxkazItgjSIDx3UEwQmOO1AEQGxJ8UPkgeGaN+aOfx28OCgJBlb43hsFp48/gttoC/gyXfLWosfRAso3tzwhSCcADPVq7GAyTgDCddD7+WZPA3sFSLHiiCmWBF5QYybn9JvY+jAyWzUsxpAjsNrE3A80Ooq3P0cpKrHE="; 192 | System.out.println(str.getBytes()); 193 | if (str.getBytes() ==miwen) { 194 | System.out.println("相等"); 195 | }else{ 196 | System.out.println("不相等"); 197 | } 198 | System.out.println(new String(RSAUtils.decryptByPrivateKey(miwen, privateKey))); 199 | 200 | // System.out.println("加密:"+new String(RSAUtils.encryptByPublicKey("13266699268".getBytes(), publicKey),"UTF-8")); 201 | // System.out.println("明文:"+new String(RSAUtils.decryptByPrivateKey(RSAUtils.encryptByPublicKey("wmsadmin@10000".getBytes(), publicKey), privateKey))); 202 | } 203 | 204 | /** 205 | * @throws Exception 206 | * @throws UnsupportedEncodingException 207 | */ 208 | public static void testOne() throws Exception, UnsupportedEncodingException { 209 | //System.out.println(Md5.getMD5Str("123456")); 210 | String key = "wmsadmin@10000"; 211 | AccessToken accessToken = new AccessToken(); 212 | accessToken.setToken("token==xxjisifdihfifdds"); 213 | accessToken.setTimestamp(new Timestamp(new Date().getTime())); 214 | putToken(key, accessToken); 215 | AccessToken accessToken2 = getToken(key); 216 | System.out.println("token:" + accessToken2.getToken()); 217 | System.out.println("isValidate:" + isVlidateToken(key)); 218 | // 219 | Map keyMap=RSAUtils.genKeyPair(); 220 | String publicKey=RSAUtils.getPublicKey(keyMap); 221 | String privateKey=RSAUtils.getPrivateKey(keyMap); 222 | 223 | String token=generateToken(publicKey,"abcdefghijklmnopqrstuvwxyz", "10000"); 224 | 225 | 226 | // 227 | System.out.println("加密:"+new String(RSAUtils.encryptByPublicKey("13266699268".getBytes(), publicKey),"UTF-8")); 228 | System.out.println("明文:"+new String(RSAUtils.decryptByPrivateKey(RSAUtils.encryptByPublicKey("wmsadmin@10000".getBytes(), publicKey), privateKey))); 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/manager/TokenManager.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.manager; 2 | 3 | import java.util.Map; 4 | 5 | import com.scienjus.authorization.model.TokenModel; 6 | 7 | /** 8 | * 对Token进行操作的接口 9 | * @author ScienJus 10 | * @date 2015/7/31. 11 | */ 12 | public interface TokenManager { 13 | 14 | /** 15 | * 创建一个token关联上指定用户 16 | * @param userId 指定用户的id 17 | * @return 生成的token 18 | */ 19 | public TokenModel createToken(long userId); 20 | 21 | /** 22 | * 检查token是否有效 23 | * @param model token 24 | * @return 是否有效 25 | */ 26 | public boolean checkToken(TokenModel model); 27 | 28 | /** 29 | * 从字符串中解析token 30 | * @param authentication 加密后的字符串 31 | * @return 32 | */ 33 | public TokenModel getToken(String authentication); 34 | 35 | /** 36 | * 清除token 37 | * @param userId 登录用户的id 38 | */ 39 | public void deleteToken(long userId); 40 | 41 | /** 42 | * 根据用户id获取token 43 | * @param userid 用户id 44 | * @return 45 | */ 46 | public Map getToken(long userId); 47 | 48 | /** 设置缓存时间 49 | * @param userId 50 | * @param time 格式 yyyy-MM-dd HH:mm:ss 51 | */ 52 | public void setTokenExpire(long userId,String time); 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/manager/impl/RedisTokenManager.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.manager.impl; 2 | 3 | import com.scienjus.authorization.manager.TokenManager; 4 | import com.scienjus.authorization.model.TokenModel; 5 | import com.scienjus.config.Constants; 6 | import com.scienjus.utils.DateFormatUtil; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.data.redis.core.RedisTemplate; 10 | import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer; 11 | import org.springframework.format.datetime.DateFormatter; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.text.ParseException; 15 | import java.text.SimpleDateFormat; 16 | import java.util.Date; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.UUID; 20 | import java.util.concurrent.TimeUnit; 21 | 22 | /** 23 | * 通过Redis存储和验证token的实现类 24 | * 25 | * @see com.scienjus.authorization.manager.TokenManager 26 | * @author ScienJus 27 | * @date 2015/7/31. 28 | */ 29 | @Component 30 | public class RedisTokenManager implements TokenManager { 31 | 32 | private RedisTemplate redis; 33 | 34 | @Autowired 35 | public void setRedis(RedisTemplate redis) { 36 | this.redis = redis; 37 | // 泛型设置成Long后必须更改对应的序列化方案 38 | redis.setKeySerializer(new JdkSerializationRedisSerializer()); 39 | } 40 | 41 | public TokenModel createToken(long userId) { 42 | // 使用uuid作为源token 43 | String token = UUID.randomUUID().toString().replace("-", ""); 44 | 45 | TokenModel model = new TokenModel(userId, token, 46 | String.valueOf(Constants.TOKEN_EXPIRES_SECONDS)); 47 | // 存储到redis并设置过期时间 48 | redis.boundValueOps(userId).set(token, Constants.TOKEN_EXPIRES_SECONDS, 49 | TimeUnit.MILLISECONDS); 50 | return model; 51 | } 52 | 53 | public TokenModel getToken(String authentication) { 54 | if (authentication == null || authentication.length() == 0) { 55 | return null; 56 | } 57 | String[] param = authentication.split("_"); 58 | if (param.length != 2) { 59 | return null; 60 | } 61 | // 使用userId和源token简单拼接成的token,可以增加加密措施 62 | long userId = Long.parseLong(param[0]); 63 | String token = param[1]; 64 | return new TokenModel(userId, token, 65 | String.valueOf(Constants.TOKEN_EXPIRES_SECONDS)); 66 | } 67 | 68 | public boolean checkToken(TokenModel model) { 69 | if (model == null) { 70 | return false; 71 | } 72 | String token = redis.boundValueOps(model.getUserId()).get(); 73 | if (token == null || !token.equals(model.getToken())) { 74 | return false; 75 | } 76 | // 如果验证成功,说明此用户进行了一次有效操作,延长token的过期时间 77 | // redis.boundValueOps(model.getUserId()).expire( 78 | // Constants.TOKEN_EXPIRES_HOUR, TimeUnit.SECONDS); 79 | return true; 80 | } 81 | 82 | public void deleteToken(long userId) { 83 | redis.delete(userId); 84 | } 85 | 86 | 87 | @Override 88 | public Map getToken(long userId) { 89 | Map tokenInfo = new HashMap(); 90 | tokenInfo.put("token", redis.boundValueOps(userId).get()); 91 | tokenInfo.put("expire", redis.boundValueOps(userId).getExpire());//秒 92 | long time= redis.boundValueOps(userId).getExpire()*1000 ;//毫秒 93 | tokenInfo.put("expire_ch",DateFormatUtil.parseMillisecone(time)); 94 | return tokenInfo; 95 | } 96 | 97 | @Override 98 | public void setTokenExpire(long userId, String dateStr) { 99 | Date startDate=new Date();//当前时间 100 | Date endDate=null; 101 | try { 102 | endDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr); 103 | } catch (ParseException e) { 104 | e.printStackTrace(); 105 | } 106 | redis.boundValueOps(userId).expire(DateFormatUtil.getDifference(startDate, endDate, 0)*1000, TimeUnit.MILLISECONDS); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/model/TokenModel.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.model; 2 | 3 | import java.util.Date; 4 | 5 | import com.scienjus.utils.DateFormatUtil; 6 | 7 | 8 | /** 9 | * Token的Model类,可以增加字段提高安全性,例如时间戳、url签名 10 | * @author ScienJus 11 | * @date 2015/7/31. 12 | */ 13 | public class TokenModel { 14 | 15 | //用户id 16 | private long userId; 17 | 18 | //随机生成的uuid 19 | private String token; 20 | 21 | private String expires;//token失效时间 22 | 23 | private long expires_in; 24 | 25 | public TokenModel(long userId, String token,String millise) { 26 | this.userId = userId; 27 | this.token = token; 28 | this.expires=DateFormatUtil.add(new Date(), "yyyy-MM-dd HH:mm:ss", Long.valueOf(millise)); 29 | this.expires_in=DateFormatUtil.addLong(new Date(), "yyyy-MM-dd HH:mm:ss", Long.valueOf(millise)); 30 | } 31 | 32 | public long getUserId() { 33 | return userId; 34 | } 35 | 36 | public void setUserId(long userId) { 37 | this.userId = userId; 38 | } 39 | 40 | public String getToken() { 41 | return token; 42 | } 43 | 44 | public void setToken(String token) { 45 | this.token = token; 46 | } 47 | 48 | public String getExpires() { 49 | return expires; 50 | } 51 | 52 | public void setExpires(String expires) { 53 | this.expires = expires; 54 | } 55 | 56 | public long getExpires_in() { 57 | return expires_in; 58 | } 59 | 60 | public void setExpires_in(long expires_in) { 61 | this.expires_in = expires_in; 62 | } 63 | 64 | 65 | 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/authorization/resolvers/CurrentUserMethodArgumentResolver.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.authorization.resolvers; 2 | 3 | import com.scienjus.authorization.annotation.CurrentUser; 4 | import com.scienjus.config.Constants; 5 | import com.scienjus.domain.User; 6 | import com.scienjus.repository.UserRepository; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.core.MethodParameter; 9 | import org.springframework.stereotype.Component; 10 | import org.springframework.web.bind.support.WebDataBinderFactory; 11 | import org.springframework.web.context.request.NativeWebRequest; 12 | import org.springframework.web.context.request.RequestAttributes; 13 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 14 | import org.springframework.web.method.support.ModelAndViewContainer; 15 | import org.springframework.web.multipart.support.MissingServletRequestPartException; 16 | 17 | /** 18 | * 增加方法注入,将含有CurrentUser注解的方法参数注入当前登录用户 19 | * @see com.scienjus.authorization.annotation.CurrentUser 20 | * @author ScienJus 21 | * @date 2015/7/31. 22 | */ 23 | @Component 24 | public class CurrentUserMethodArgumentResolver implements HandlerMethodArgumentResolver { 25 | 26 | @Autowired 27 | private UserRepository userRepository; 28 | 29 | @Override 30 | public boolean supportsParameter(MethodParameter parameter) { 31 | //如果参数类型是User并且有CurrentUser注解则支持 32 | if (parameter.getParameterType().isAssignableFrom(User.class) && 33 | parameter.hasParameterAnnotation(CurrentUser.class)) { 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | @Override 40 | public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { 41 | //取出鉴权时存入的登录用户Id 42 | Long currentUserId = (Long) webRequest.getAttribute(Constants.CURRENT_USER_ID, RequestAttributes.SCOPE_REQUEST); 43 | if (currentUserId != null) { 44 | //从数据库中查询并返回 45 | return userRepository.findOne(currentUserId); 46 | } 47 | throw new MissingServletRequestPartException(Constants.CURRENT_USER_ID); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/config/Constants.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.config; 2 | 3 | /** 4 | * 常量 5 | * @author ScienJus 6 | * @date 2015/7/31. 7 | */ 8 | public class Constants { 9 | 10 | /** 11 | * 存储当前登录用户id的字段名 12 | */ 13 | public static final String CURRENT_USER_ID = "CURRENT_USER_ID"; 14 | 15 | /** 16 | * token有效期(小时) 17 | */ 18 | public static final int TOKEN_EXPIRES_HOUR = 30*1*60*60;//天时分秒 19 | 20 | public static final int TOKEN_EXPIRES_SECONDS = 7*24*60*60*1000;//天时分秒 21 | 22 | /** 23 | * 存放Authorization的header字段 24 | */ 25 | public static final String AUTHORIZATION = "authorization"; 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.config; 2 | 3 | import com.scienjus.authorization.interceptor.AuthorizationInterceptor; 4 | import com.scienjus.authorization.resolvers.CurrentUserMethodArgumentResolver; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 8 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 9 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 10 | 11 | import java.util.List; 12 | 13 | /** 14 | * 配置类,增加自定义拦截器和解析器 15 | * @see com.scienjus.authorization.resolvers.CurrentUserMethodArgumentResolver 16 | * @see com.scienjus.authorization.interceptor.AuthorizationInterceptor 17 | * @author ScienJus 18 | * @date 2015/7/30. 19 | */ 20 | @Configuration 21 | public class MvcConfig extends WebMvcConfigurerAdapter { 22 | 23 | @Autowired 24 | private AuthorizationInterceptor authorizationInterceptor; 25 | 26 | @Autowired 27 | private CurrentUserMethodArgumentResolver currentUserMethodArgumentResolver; 28 | 29 | @Override 30 | public void addInterceptors(InterceptorRegistry registry) { 31 | registry.addInterceptor(authorizationInterceptor); 32 | } 33 | 34 | @Override 35 | public void addArgumentResolvers(List argumentResolvers) { 36 | argumentResolvers.add(currentUserMethodArgumentResolver); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/config/ResultStatus.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.config; 2 | 3 | /** 4 | * 自定义请求状态码 5 | * @author ScienJus 6 | * @date 2015/7/15. 7 | */ 8 | public enum ResultStatus { 9 | SUCCESS(100, "成功"), 10 | USERNAME_OR_PASSWORD_ERROR(-1001, "用户名或密码错误"), 11 | USER_NOT_FOUND(-1002, "用户不存在"), 12 | USER_NOT_LOGIN(-1003, "用户未登录"), 13 | TOKEN_OUT_TIME(-1003, "Token时间过期,请重新登录!"); 14 | 15 | /** 16 | * 返回码 17 | */ 18 | private int code; 19 | 20 | /** 21 | * 返回结果描述 22 | */ 23 | private String message; 24 | 25 | ResultStatus(int code, String message) { 26 | this.code = code; 27 | this.message = message; 28 | } 29 | 30 | public int getCode() { 31 | return code; 32 | } 33 | 34 | public void setCode(int code) { 35 | this.code = code; 36 | } 37 | 38 | public String getMessage() { 39 | return message; 40 | } 41 | 42 | public void setMessage(String message) { 43 | this.message = message; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/config/SwaggerConfig.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.config; 2 | 3 | import com.mangofactory.swagger.configuration.SpringSwaggerConfig; 4 | import com.mangofactory.swagger.models.dto.ApiInfo; 5 | import com.mangofactory.swagger.paths.AbsoluteSwaggerPathProvider; 6 | import com.mangofactory.swagger.paths.RelativeSwaggerPathProvider; 7 | import com.mangofactory.swagger.plugin.EnableSwagger; 8 | import com.mangofactory.swagger.plugin.SwaggerSpringMvcPlugin; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.context.annotation.Bean; 11 | import org.springframework.context.annotation.Configuration; 12 | 13 | import java.sql.Timestamp; 14 | 15 | /** 16 | * swagger-ui的配置 17 | * @author ScienJus 18 | * @date 2015/7/10. 19 | */ 20 | @Configuration 21 | @EnableSwagger 22 | public class SwaggerConfig { 23 | 24 | private SpringSwaggerConfig springSwaggerConfig; 25 | 26 | @Autowired 27 | public void setSpringSwaggerConfig(SpringSwaggerConfig springSwaggerConfig) { 28 | this.springSwaggerConfig = springSwaggerConfig; 29 | } 30 | 31 | @Bean 32 | public SwaggerSpringMvcPlugin customImplementation() { 33 | System.out.println("base path="+springSwaggerConfig.defaultSwaggerPathProvider().getApplicationBasePath()); 34 | return new SwaggerSpringMvcPlugin(this.springSwaggerConfig) 35 | .apiInfo(new ApiInfo("spring-token-restful api doc", 36 | null, null, null, null, null)). 37 | //将Timestamp类型全部转为Long类型 38 | directModelSubstitute(Timestamp.class, Long.class); 39 | 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/controller/TokenController.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.controller; 2 | 3 | import com.scienjus.authorization.annotation.Authorization; 4 | import com.scienjus.authorization.annotation.CurrentUser; 5 | import com.scienjus.authorization.manager.TokenManager; 6 | import com.scienjus.authorization.model.TokenModel; 7 | import com.scienjus.config.ResultStatus; 8 | import com.scienjus.domain.User; 9 | import com.scienjus.model.ResultModel; 10 | import com.scienjus.repository.UserRepository; 11 | import com.wordnik.swagger.annotations.ApiImplicitParam; 12 | import com.wordnik.swagger.annotations.ApiImplicitParams; 13 | import com.wordnik.swagger.annotations.ApiOperation; 14 | 15 | import org.apache.tomcat.util.buf.UDecoder; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.http.HttpStatus; 18 | import org.springframework.http.ResponseEntity; 19 | import org.springframework.util.Assert; 20 | import org.springframework.web.bind.annotation.PathVariable; 21 | import org.springframework.web.bind.annotation.RequestMapping; 22 | import org.springframework.web.bind.annotation.RequestMethod; 23 | import org.springframework.web.bind.annotation.RequestParam; 24 | import org.springframework.web.bind.annotation.RestController; 25 | 26 | /** 27 | * 获取和删除token的请求地址,在Restful设计中其实就对应着登录和退出登录的资源映射 28 | * @author ScienJus 29 | * @date 2015/7/30. 30 | */ 31 | @RestController 32 | @RequestMapping("/tokens") 33 | public class TokenController { 34 | 35 | @Autowired 36 | private UserRepository userRepository; 37 | 38 | @Autowired 39 | private TokenManager tokenManager; 40 | 41 | @RequestMapping(method = RequestMethod.POST,produces = "application/json; charset=utf-8") 42 | @ApiOperation(value = "登录") 43 | public ResponseEntity login(@RequestParam String username, @RequestParam String password) { 44 | Assert.notNull(username, "username can not be empty"); 45 | Assert.notNull(password, "password can not be empty"); 46 | System.out.println("用户名:"+username+" 密码:"+password+" 转码:"+UDecoder.URLDecode(username)); 47 | User user = userRepository.findByUsername(username); 48 | if (user == null || //未注册 49 | !user.getPassword().equals(password)) { //密码错误 50 | //提示用户名或密码错误 51 | return new ResponseEntity<>(ResultModel.error(ResultStatus.USERNAME_OR_PASSWORD_ERROR), HttpStatus.NOT_FOUND); 52 | } 53 | //生成一个token,保存用户登录状态 54 | TokenModel model = tokenManager.createToken(user.getId()); 55 | return new ResponseEntity<>(ResultModel.ok(model), HttpStatus.OK); 56 | } 57 | 58 | @RequestMapping(method = RequestMethod.DELETE) 59 | @Authorization 60 | @ApiOperation(value = "退出登录") 61 | @ApiImplicitParams({ 62 | @ApiImplicitParam(name = "authorization", value = "authorization", required = true, dataType = "string", paramType = "header"), 63 | }) 64 | public ResponseEntity logout(@CurrentUser User user) { 65 | tokenManager.deleteToken(user.getId()); 66 | return new ResponseEntity<>(ResultModel.ok(), HttpStatus.OK); 67 | } 68 | 69 | @RequestMapping(method = RequestMethod.GET) 70 | @Authorization 71 | @ApiOperation(value = "获取用户信息") 72 | @ApiImplicitParams({ 73 | @ApiImplicitParam(name = "authorization", value = "authorization", required = true, dataType = "string", paramType = "header"), 74 | }) 75 | public ResponseEntity getUserInfo(@CurrentUser User user){ 76 | User userModel = userRepository.findById(user.getId()); 77 | return new ResponseEntity<>(userModel, HttpStatus.OK); 78 | } 79 | 80 | @RequestMapping(method = RequestMethod.GET,value="/user/{user_id}/{id}") 81 | public ResponseEntity getUser(@PathVariable int user_id,@PathVariable Long id){ 82 | User userModel = userRepository.findById(user_id); 83 | System.out.println("id="+id); 84 | return new ResponseEntity<>(userModel, HttpStatus.OK); 85 | } 86 | 87 | @ApiOperation(value = "获取Token值") 88 | @RequestMapping(method = RequestMethod.POST,value="/{user_id}") 89 | public ResponseEntity getTokens(@PathVariable int user_id){ 90 | return new ResponseEntity<>(ResultModel.ok(tokenManager.getToken(user_id)), HttpStatus.OK); 91 | } 92 | 93 | @ApiOperation(value = "设置Token的缓存时间") 94 | @RequestMapping(method = RequestMethod.GET,value="/setTokens/{user_id}") 95 | public ResponseEntity setTokens(@PathVariable int user_id,@RequestParam String time){ 96 | if(tokenManager.getToken(user_id).get("token")!=null){ 97 | tokenManager.setTokenExpire(user_id, time); 98 | return new ResponseEntity<>(ResultModel.ok(), HttpStatus.OK); 99 | }else{ 100 | return new ResponseEntity<>(ResultModel.error(ResultStatus.TOKEN_OUT_TIME), HttpStatus.OK); 101 | } 102 | 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/domain/User.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.domain; 2 | 3 | import javax.persistence.Column; 4 | import javax.persistence.Entity; 5 | import javax.persistence.Id; 6 | import javax.persistence.Table; 7 | 8 | /** 9 | * 用户数据的domain类 10 | * @author ScienJus 11 | * @date 2015/7/31. 12 | */ 13 | @Entity 14 | @Table(name = "tbl_user") 15 | public class User { 16 | //用户名 17 | @Column(name = "username") 18 | private String username; 19 | 20 | //密码 21 | @Column(name = "password") 22 | private String password; 23 | 24 | //用户id 25 | @Id 26 | @Column(name = "id") 27 | private long id; 28 | 29 | //昵称 30 | @Column(name = "nickname") 31 | private String nickname; 32 | 33 | public String getUsername() { 34 | return username; 35 | } 36 | 37 | public void setUsername(String username) { 38 | this.username = username; 39 | } 40 | 41 | public String getPassword() { 42 | return password; 43 | } 44 | 45 | public void setPassword(String password) { 46 | this.password = password; 47 | } 48 | 49 | public long getId() { 50 | return id; 51 | } 52 | 53 | public void setId(long id) { 54 | this.id = id; 55 | } 56 | 57 | public String getNickname() { 58 | return nickname; 59 | } 60 | 61 | public void setNickname(String nickname) { 62 | this.nickname = nickname; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/model/AccessToken.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.model; 2 | 3 | import java.io.Serializable; 4 | import java.sql.Timestamp; 5 | 6 | /** 7 | * SAAS Token WMS管理实体 8 | * 9 | * @packge com.wlyd.wmscloud.persistence.beans.api.AccessToken 10 | * @date 2016年5月6日 上午10:27:55 11 | * @author pengjunlin 12 | * @comment 13 | * @update 14 | */ 15 | public class AccessToken implements Serializable{ 16 | 17 | /** 18 | * 19 | */ 20 | private static final long serialVersionUID = 4759692267927548118L; 21 | 22 | private String token;// AccessToken字符串 23 | 24 | private Timestamp timestamp;// 时间戳(用于验证token和重新获取token) 25 | 26 | public String getToken() { 27 | return token; 28 | } 29 | 30 | public void setToken(String token) { 31 | this.token = token; 32 | } 33 | 34 | public Timestamp getTimestamp() { 35 | return timestamp; 36 | } 37 | 38 | public void setTimestamp(Timestamp timestamp) { 39 | this.timestamp = timestamp; 40 | } 41 | 42 | public long getLongTime(){ 43 | if(timestamp!=null){ 44 | return timestamp.getTime(); 45 | } 46 | return 0; 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /src/main/java/com/scienjus/model/ResultModel.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.model; 2 | 3 | import com.scienjus.config.ResultStatus; 4 | 5 | /** 6 | * 自定义返回结果 7 | * @author XieEnlong 8 | * @date 2015/7/14. 9 | */ 10 | public class ResultModel { 11 | 12 | /** 13 | * 返回码 14 | */ 15 | private int code; 16 | 17 | /** 18 | * 返回结果描述 19 | */ 20 | private String message; 21 | 22 | /** 23 | * 返回内容 24 | */ 25 | private Object content; 26 | 27 | public int getCode() { 28 | return code; 29 | } 30 | 31 | public String getMessage() { 32 | return message; 33 | } 34 | 35 | public Object getContent() { 36 | return content; 37 | } 38 | 39 | public ResultModel(int code, String message) { 40 | this.code = code; 41 | this.message = message; 42 | this.content = ""; 43 | } 44 | 45 | public ResultModel(int code, String message, Object content) { 46 | this.code = code; 47 | this.message = message; 48 | this.content = content; 49 | } 50 | 51 | public ResultModel(ResultStatus status) { 52 | this.code = status.getCode(); 53 | this.message = status.getMessage(); 54 | this.content = ""; 55 | } 56 | 57 | public ResultModel(ResultStatus status, Object content) { 58 | this.code = status.getCode(); 59 | this.message = status.getMessage(); 60 | this.content = content; 61 | } 62 | 63 | public static ResultModel ok(Object content) { 64 | return new ResultModel(ResultStatus.SUCCESS, content); 65 | } 66 | 67 | public static ResultModel ok() { 68 | return new ResultModel(ResultStatus.SUCCESS); 69 | } 70 | 71 | public static ResultModel error(ResultStatus error) { 72 | return new ResultModel(error); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.repository; 2 | 3 | import com.scienjus.domain.User; 4 | import org.springframework.data.repository.CrudRepository; 5 | 6 | /** 7 | * User类的CRUD操作 8 | * @see com.scienjus.domain.User 9 | * @author ScienJus 10 | * @date 2015/7/10. 11 | */ 12 | public interface UserRepository extends CrudRepository { 13 | 14 | public User findByUsername(String username); 15 | 16 | public User findById(long id); 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/utils/Base64Utils.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.utils; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.File; 6 | import java.io.FileInputStream; 7 | import java.io.FileOutputStream; 8 | import java.io.InputStream; 9 | import java.io.OutputStream; 10 | 11 | import it.sauronsoftware.base64.Base64; 12 | 13 | /** 14 | *

15 | * BASE64编码解码工具包 16 | *

17 | *

18 | * 依赖javabase64-1.3.1.jar 19 | *

20 | * 21 | * @author IceWee 22 | * @date 2012-5-19 23 | * @version 1.0 24 | */ 25 | public class Base64Utils { 26 | 27 | /** 28 | * 文件读取缓冲区大小 29 | */ 30 | private static final int CACHE_SIZE = 1024; 31 | 32 | /** 33 | *

34 | * BASE64字符串解码为二进制数据 35 | *

36 | * 37 | * @param base64 38 | * @return 39 | * @throws Exception 40 | */ 41 | public static byte[] decode(String base64) throws Exception { 42 | return Base64.decode(base64.getBytes()); 43 | } 44 | 45 | /** 46 | *

47 | * 二进制数据编码为BASE64字符串 48 | *

49 | * 50 | * @param bytes 51 | * @return 52 | * @throws Exception 53 | */ 54 | public static String encode(byte[] bytes) throws Exception { 55 | return new String(Base64.encode(bytes)); 56 | } 57 | 58 | /** 59 | *

60 | * 将文件编码为BASE64字符串 61 | *

62 | *

63 | * 大文件慎用,可能会导致内存溢出 64 | *

65 | * 66 | * @param filePath 文件绝对路径 67 | * @return 68 | * @throws Exception 69 | */ 70 | public static String encodeFile(String filePath) throws Exception { 71 | byte[] bytes = fileToByte(filePath); 72 | return encode(bytes); 73 | } 74 | 75 | /** 76 | *

77 | * BASE64字符串转回文件 78 | *

79 | * 80 | * @param filePath 文件绝对路径 81 | * @param base64 编码字符串 82 | * @throws Exception 83 | */ 84 | public static void decodeToFile(String filePath, String base64) throws Exception { 85 | byte[] bytes = decode(base64); 86 | byteArrayToFile(bytes, filePath); 87 | } 88 | 89 | /** 90 | *

91 | * 文件转换为二进制数组 92 | *

93 | * 94 | * @param filePath 文件路径 95 | * @return 96 | * @throws Exception 97 | */ 98 | public static byte[] fileToByte(String filePath) throws Exception { 99 | byte[] data = new byte[0]; 100 | File file = new File(filePath); 101 | if (file.exists()) { 102 | FileInputStream in = new FileInputStream(file); 103 | ByteArrayOutputStream out = new ByteArrayOutputStream(2048); 104 | byte[] cache = new byte[CACHE_SIZE]; 105 | int nRead = 0; 106 | while ((nRead = in.read(cache)) != -1) { 107 | out.write(cache, 0, nRead); 108 | out.flush(); 109 | } 110 | out.close(); 111 | in.close(); 112 | data = out.toByteArray(); 113 | } 114 | return data; 115 | } 116 | 117 | /** 118 | *

119 | * 二进制数据写文件 120 | *

121 | * 122 | * @param bytes 二进制数据 123 | * @param filePath 文件生成目录 124 | */ 125 | public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception { 126 | InputStream in = new ByteArrayInputStream(bytes); 127 | File destFile = new File(filePath); 128 | if (!destFile.getParentFile().exists()) { 129 | destFile.getParentFile().mkdirs(); 130 | } 131 | destFile.createNewFile(); 132 | OutputStream out = new FileOutputStream(destFile); 133 | byte[] cache = new byte[CACHE_SIZE]; 134 | int nRead = 0; 135 | while ((nRead = in.read(cache)) != -1) { 136 | out.write(cache, 0, nRead); 137 | out.flush(); 138 | } 139 | out.close(); 140 | in.close(); 141 | } 142 | 143 | 144 | } -------------------------------------------------------------------------------- /src/main/java/com/scienjus/utils/DateFormatUtil.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.utils; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | import java.util.GregorianCalendar; 8 | 9 | /** 10 | * 11 | *

12 | * 时间转换工具类 13 | *

14 | * 15 | * 16 | */ 17 | public class DateFormatUtil { 18 | 19 | /** 格式:yyyy-MM-dd */ 20 | public static SimpleDateFormat yyyy_MM_dd = new SimpleDateFormat( 21 | "yyyy-MM-dd"); 22 | /** 格式:yyyyMMdd */ 23 | public static SimpleDateFormat yyyyMMdd = new SimpleDateFormat("yyyyMMdd"); 24 | /** 格式:yyyy/MM/dd */ 25 | public static SimpleDateFormat _yyyy_MM_dd = new SimpleDateFormat( 26 | "yyyy/MM/dd"); 27 | 28 | /** 格式:yyyy-MM-dd HH:mm:ss */ 29 | public static SimpleDateFormat yMd_Hms = new SimpleDateFormat( 30 | "yyyy-MM-dd HH:mm:ss"); 31 | /** 格式:yyyy/MM/dd HH:mm:ss */ 32 | public static SimpleDateFormat _yMd_Hms = new SimpleDateFormat( 33 | "yyyy/MM/dd HH:mm:ss"); 34 | /** 格式:yyyyMMddHHmmss */ 35 | public static SimpleDateFormat yMdHms = new SimpleDateFormat( 36 | "yyyyMMddHHmmss"); 37 | 38 | /** 格式:yyyyMM */ 39 | public static SimpleDateFormat yyyyMM = new SimpleDateFormat("yyyyMM"); 40 | /** 格式:HH:mm:ss */ 41 | public static SimpleDateFormat HHmmss = new SimpleDateFormat("HH:mm:ss"); 42 | 43 | /** 44 | *

45 | * 获取当前系统时间 46 | *

47 | * 通过java.util.Date类获取 48 | * 49 | * @return 返回java.util.Date类型对象 50 | * @see #getCurrentDate() 51 | */ 52 | public static Date getDate() { 53 | return new Date(); 54 | } 55 | 56 | /** 57 | *

58 | * 获取当前系统时间 59 | *

60 | * 通过java.util.Calendar类获取 61 | * 62 | * @return 返回java.util.Date类型对象 63 | * @see Calendar 64 | */ 65 | public static Date getCalendarDate() { 66 | Calendar calendar = Calendar.getInstance(); 67 | return calendar.getTime(); 68 | } 69 | 70 | /** 71 | *

72 | * 获取当前系统日期,返回字符串格式 73 | *

74 | * 格式:yyyy-MM-dd 75 | * 76 | * @return 返回日期字符串格式:yyyy-MM-dd 77 | * @see #getDateStr(Date) 78 | */ 79 | public static String getDateStr() { 80 | return getDateStr(new Date()); 81 | } 82 | 83 | /** 84 | *

85 | * 获取格式化字符串日期,返回字符串格式 86 | *

87 | * 格式:yyyy-MM-dd 88 | * 89 | * @param date 90 | * 指定日期对象 91 | * @return 返回日期字符串格式:yyyy-MM-dd 92 | */ 93 | public static String getDateStr(Date date) { 94 | return yyyy_MM_dd.format(date); 95 | } 96 | 97 | /** 98 | *

99 | * [默认] 获取当前系统日期时间,返回字符串格式 100 | *

101 | * 格式:yyyy-MM-dd HH:mm:ss
102 | * 103 | * @return 返回字符串对象:yyyy-MM-dd HH:mm:ss 104 | * @see #getDateTimeStr(Date) 105 | */ 106 | public static String getDateTime() { 107 | return yMd_Hms.format(new Date()); 108 | } 109 | 110 | /** 111 | *

112 | * 获取当前系统日期时间,返回字符串格式 113 | *

114 | * 格式:yyyy-MM-dd HH:mm:ss 115 | * 116 | * @return 返回字符串对象:yyyy-MM-dd HH:mm:ss 117 | * @see #getDateTimeStr(Date) 118 | */ 119 | public static String getDateTimeStr() { 120 | return getDateTimeStr(new Date()); 121 | } 122 | 123 | /** 124 | *

125 | * 获取格式化字符串日期时间,返回字符串格式 126 | *

127 | * 格式:yyyy-MM-dd HH:mm:ss 128 | * 129 | * @param date 130 | * 指定日期对象 131 | * @return 返回日期时间字符串格式:yyyy-MM-dd HH:mm:ss 132 | */ 133 | public static String getDateTimeStr(Date date) { 134 | return yMd_Hms.format(date); 135 | } 136 | 137 | /** 138 | *

139 | * 获取当前年 140 | *

141 | * 142 | * @return 返回int类型的整数 143 | */ 144 | public static int getCurrentYear() { 145 | Calendar c = Calendar.getInstance(); 146 | return c.get(Calendar.YEAR); 147 | } 148 | 149 | /** 150 | * 151 | *

152 | * 获取当前月 153 | *

154 | * 155 | * @return 返回int类型的整数,一位或两位数,范围是:1-12 156 | */ 157 | public static int getCurrentMonth() { 158 | Calendar c = Calendar.getInstance(); 159 | return c.get(Calendar.MONTH) + 1; 160 | } 161 | 162 | // 获得本月第一天0点时间 163 | public static Date getTimesMonthmorning() { 164 | Calendar cal = Calendar.getInstance(); 165 | cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), 166 | cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0); 167 | cal.set(Calendar.DAY_OF_MONTH, 168 | cal.getActualMinimum(Calendar.DAY_OF_MONTH)); 169 | return cal.getTime(); 170 | } 171 | 172 | public static Date getLastMonthStartMorning() { 173 | Calendar cal = Calendar.getInstance(); 174 | cal.setTime(getTimesMonthmorning()); 175 | cal.add(Calendar.MONTH, -1); 176 | return cal.getTime(); 177 | } 178 | 179 | /** 180 | *

181 | * 获取当前日 182 | *

183 | * 184 | * @return 返回int类型的整数,一位或两位数,范围是:1-31 185 | */ 186 | public static int getCurrentDay() { 187 | Calendar c = Calendar.getInstance(); 188 | return c.get(Calendar.DAY_OF_MONTH); 189 | } 190 | 191 | /** 192 | *

193 | * 获得指定的年,int格式 194 | *

195 | * 196 | * @param date 197 | * 指定日期对象 198 | * @return 返回int类型的整数 199 | */ 200 | public static int getCustomYear(Date date) { 201 | Calendar c = Calendar.getInstance(); 202 | c.setTime(date); 203 | return c.get(Calendar.YEAR); 204 | } 205 | 206 | /** 207 | *

208 | * 获得指定的月,int格式 209 | *

210 | * 211 | * @param date 212 | * 指定日期对象 213 | * @return 返回int类型的整数,一位或两位数,范围是:1-12 214 | */ 215 | public static int getCustomMonth(Date date) { 216 | Calendar c = Calendar.getInstance(); 217 | c.setTime(date); 218 | return c.get(Calendar.MONTH) + 1; 219 | } 220 | 221 | /** 222 | *

223 | * 获得指定的日,int格式 224 | *

225 | * 226 | * @param date 227 | * 指定日期对象 228 | * @return 返回int类型的整数,一位或两位数,范围是:1-31 229 | */ 230 | public static int getCustomDay(Date date) { 231 | Calendar c = Calendar.getInstance(); 232 | c.setTime(date); 233 | return c.get(Calendar.DAY_OF_MONTH); 234 | } 235 | 236 | /** 237 | *

238 | * 获取当前系统时间的小时数 239 | *

240 | * 通过java.util.Calendar获取 241 | * 242 | * @return 返回小时数 243 | */ 244 | public static int getCurrentHour() { 245 | Calendar calendar = new GregorianCalendar(); 246 | return calendar.get(Calendar.HOUR_OF_DAY); 247 | } 248 | 249 | /** 250 | *

251 | * 获取当前系统时间的分钟数 252 | *

253 | * 通过java.util.Calendar获取 254 | * 255 | * @return 返回分钟数 256 | */ 257 | public static int getCurrentMinute() { 258 | Calendar calendar = new GregorianCalendar(); 259 | return calendar.get(Calendar.MINUTE); 260 | } 261 | 262 | /** 263 | *

264 | * 获取当前系统时间的秒数 265 | *

266 | * 通过java.util.Calendar获取 267 | * 268 | * @return 返回秒数 269 | */ 270 | public static int getCurrentSecond() { 271 | Calendar calendar = new GregorianCalendar(); 272 | return calendar.get(Calendar.SECOND); 273 | } 274 | 275 | /** 276 | *

277 | * 获得指定的小时(日中的),int格式 278 | *

279 | *
280 | * 281 | * @return 282 | */ 283 | public static int getCustomHour(Date date) { 284 | Calendar c = Calendar.getInstance(); 285 | c.setTime(date); 286 | return c.get(Calendar.HOUR_OF_DAY); 287 | } 288 | 289 | /** 290 | *

291 | * 获得指定的分钟,int格式 292 | *

293 | *
294 | * 295 | * @return 296 | */ 297 | public static int getCustomMinute(Date date) { 298 | Calendar c = Calendar.getInstance(); 299 | c.setTime(date); 300 | return c.get(Calendar.MINUTE); 301 | } 302 | 303 | /** 304 | *

305 | * 获得指定的秒,int格式 306 | *

307 | *
308 | * 309 | * @return 310 | */ 311 | public static int getCustomSecond(Date date) { 312 | Calendar c = Calendar.getInstance(); 313 | c.setTime(date); 314 | return c.get(Calendar.SECOND); 315 | } 316 | 317 | /********************** 我是华丽丽的分割线 ***************************************************/ 318 | 319 | /** 320 | *

321 | * 获取本月第一天日期(格式如YYYYMMDD),如果当前日为当月1日,则返回上月第一日 322 | *

323 | * 324 | * @return 325 | */ 326 | public static String getMonthFirstDay() { 327 | Calendar calendar = new GregorianCalendar(); 328 | int day = calendar.get(Calendar.DAY_OF_MONTH); 329 | int month = 0; 330 | if (day == 1)// 当月第一日 331 | { 332 | calendar.add(Calendar.MONTH, -1); 333 | } 334 | month = calendar.get(Calendar.MONTH); 335 | if (month < 10) { 336 | return "" + calendar.get(Calendar.YEAR) + "0" + (month + 1) + "01"; 337 | } else { 338 | return "" + calendar.get(Calendar.YEAR) + month + "01"; 339 | } 340 | } 341 | 342 | /** 343 | *

344 | * 获取当前时间前几天或后几天的日期 345 | *

346 | * 347 | * @return 348 | */ 349 | public static Date getAddDays(int days) { 350 | Calendar calendar = new GregorianCalendar(); 351 | calendar.add(Calendar.DAY_OF_YEAR, days); 352 | return calendar.getTime(); 353 | } 354 | 355 | /** 356 | *

357 | * 获取某个月后的日期格式(yyyyMMdd) 358 | *

359 | * 360 | * @return 361 | */ 362 | public static String getAfterMonth(int monthNum) { 363 | Calendar calendar = new GregorianCalendar(); 364 | calendar.add(Calendar.MONTH, monthNum); 365 | return yyyyMMdd.format(calendar.getTime()); 366 | } 367 | 368 | /** 369 | *

370 | * 返回日期(格式yyyyMMdd) 371 | *

372 | * 373 | * @param timeMillis 374 | * @return 375 | */ 376 | public static String getFormatDate(long timeMillis) { 377 | return yMdHms.format(new Date(timeMillis)); 378 | } 379 | 380 | /** 381 | * 获取当前系统时间距离传入时间的毫秒数 382 | * 383 | * @param strTime 384 | * 格式[ DD:00:00] 385 | * @return 386 | * @throws ParseException 387 | */ 388 | public static long getSleepTime(String strTime) throws ParseException { 389 | long p = 1; 390 | long l_date = System.currentTimeMillis(); 391 | Date date_now = new Date(l_date); 392 | String strDate = yyyy_MM_dd.format(date_now) + strTime; 393 | if (date_now.before(yMd_Hms.parse(strDate))) 394 | p = (yMd_Hms.parse(strDate)).getTime() - l_date; 395 | else { 396 | Calendar calendar = new GregorianCalendar(); 397 | calendar.setTime(date_now); 398 | calendar.add(Calendar.DAY_OF_YEAR, 1); 399 | Date date = calendar.getTime(); 400 | strDate = yyyy_MM_dd.format(date) + strTime; 401 | p = (yMd_Hms.parse(strDate)).getTime() - l_date; 402 | } 403 | return p; 404 | } 405 | 406 | public static String getPredate() { 407 | Date nowDate = new Date(); 408 | String nowdates = yyyy_MM_dd.format(nowDate); 409 | String[] dates = nowdates.split("-"); 410 | int year = Integer.parseInt(dates[0]); 411 | int month = Integer.parseInt(dates[1]); 412 | int day = Integer.parseInt(dates[2]) - 1; 413 | if (day == 0) { 414 | switch (month - 1) { 415 | case 1: 416 | day = 31; 417 | break; 418 | case 3: 419 | day = 31; 420 | break; 421 | case 5: 422 | day = 31; 423 | break; 424 | case 7: 425 | day = 31; 426 | break; 427 | case 8: 428 | day = 31; 429 | break; 430 | case 10: 431 | day = 31; 432 | break; 433 | case 0: 434 | month = 13; 435 | year = year - 1; 436 | day = 31; 437 | break; 438 | case 4: 439 | day = 30; 440 | break; 441 | case 6: 442 | day = 30; 443 | break; 444 | case 9: 445 | day = 30; 446 | break; 447 | case 11: 448 | day = 30; 449 | break; 450 | case 2: 451 | if (year % 4 == 0) { 452 | day = 29; 453 | } else { 454 | day = 28; 455 | } 456 | break; 457 | default: 458 | break; 459 | } 460 | month = month - 1; 461 | } 462 | String predate = Integer.toString(year) + "-" 463 | + (month < 10 ? "0" + month : month) + "-" 464 | + (day < 10 ? "0" + day : day); 465 | return predate; 466 | } 467 | 468 | /** 469 | *

470 | * 获取中文日期格式 471 | *

472 | * 格式:xxxx年xx月xx日 473 | * 474 | * @param date 475 | * @return 476 | */ 477 | /* 478 | * public static String getChinaDateFormat(Date date) { // 479 | * 获取yyyy-mm-dd格式日期格式 String dateStr = getDateTime_I(date); StringBuffer sb 480 | * = new StringBuffer(); if (dateStr != null && dateStr.length() > 0) { 481 | * String[] newStr = dateStr.split("-"); // 获取月 int month = 482 | * Integer.valueOf(newStr[1]); // 获取日 int day = Integer.valueOf(newStr[2]); 483 | * sb.append(newStr[0]).append("年"); 484 | * sb.append(month).append("月").append(day).append("日"); } return 485 | * sb.toString(); } 486 | */ 487 | 488 | /** 489 | *

490 | * 获取中文日期时间格式 491 | *

492 | * 格式:xxxx年xx月xx日
493 | * 494 | * @param date 495 | * 指定日期对象,为null时获取当前系统时间 496 | * @return 返回诸如“xxxx年xx月xx日”格式的日期 497 | */ 498 | public static String getChineseDate(Date date) { 499 | if (date == null) 500 | date = new Date(); 501 | int yyyy = getCustomYear(date); 502 | int MM = getCustomMonth(date); 503 | int dd = getCustomDay(date); 504 | 505 | StringBuilder sb = new StringBuilder(); 506 | sb.append(yyyy + "年"); 507 | sb.append(MM + "月"); 508 | sb.append(dd + "日"); 509 | return sb.toString(); 510 | } 511 | 512 | /** 513 | *

514 | * 获取中文日期时间格式 515 | *

516 | * 格式:xxxx年xx月xx日 xx时xx分xx秒 517 | * 518 | * @param date 519 | * 指定日期对象,为null时获取当前系统时间 520 | * @return 返回诸如“xxxx年xx月xx日 xx时xx分xx秒”格式的日期 521 | */ 522 | public static String getChineseDateTime(Date date) { 523 | if (date == null) 524 | date = new Date(); 525 | int yyyy = getCustomYear(date); 526 | int MM = getCustomMonth(date); 527 | int dd = getCustomDay(date); 528 | 529 | int HH = getCustomHour(date); 530 | int mm = getCustomMinute(date); 531 | int ss = getCustomSecond(date); 532 | 533 | StringBuilder sb = new StringBuilder(); 534 | sb.append(yyyy + "年"); 535 | sb.append(MM + "月"); 536 | sb.append(dd + "日"); 537 | sb.append(" "); 538 | sb.append(HH + "时"); 539 | sb.append(mm + "分"); 540 | sb.append(ss + "秒"); 541 | 542 | return sb.toString(); 543 | } 544 | 545 | /** 546 | * add by lipp 547 | *

548 | * 获取xxxx年xx月xx日 日期格式。 549 | *

550 | * 551 | * @param date 552 | * 格式必须是2009-03-21字符串 553 | * @return 554 | */ 555 | public static String getChinaDateFormat(String date) { 556 | // 获取yyyy-mm-dd格式日期格式 557 | StringBuffer sb = new StringBuffer(); 558 | if (date != null && date.length() > 0) { 559 | String[] newStr = date.split("-"); 560 | // 获取月 561 | int month = Integer.valueOf(newStr[1]); 562 | // 获取日 563 | int day = Integer.valueOf(newStr[2]); 564 | sb.append(newStr[0]).append("年"); 565 | sb.append(month).append("月").append(day).append("日"); 566 | } 567 | return sb.toString(); 568 | } 569 | 570 | /** 571 | * 判断一个日期字符串是否合法 572 | * 573 | * @param date 574 | * @param format 575 | * @return 576 | * @author liufengyu 577 | */ 578 | public static boolean isDateStringCorrect(String date, String format) { 579 | SimpleDateFormat df = new SimpleDateFormat(format); 580 | 581 | try { 582 | df.setLenient(false); 583 | df.parse(date); 584 | return true; 585 | } catch (Exception e) { 586 | return false; 587 | } 588 | } 589 | 590 | /** 591 | * add by gongtao 592 | *

593 | * 将字符串类型的日期格式 转换为 符合要求的日期格式 594 | *

595 | * 596 | * @param date 597 | * @param format 598 | * @return 599 | */ 600 | public static String getStrDate4String(String date, String format) { 601 | if (date == null || date.trim().equals("")) { 602 | return ""; 603 | } else { 604 | SimpleDateFormat df = new SimpleDateFormat(format); 605 | try { 606 | Date d = df.parse(date); 607 | return df.format(d); 608 | } catch (ParseException e) { 609 | System.out.println(e); 610 | return ""; 611 | } 612 | } 613 | } 614 | 615 | /** 616 | * add by gongtao 617 | *

618 | * 将Date类型的日期格式 转换为 符合要求的 String日期格式 619 | *

620 | * 621 | * @param date 622 | * @param format 623 | * @return 624 | */ 625 | public static String getStrDate4Date(Date date, String format) { 626 | if (date == null) { 627 | return ""; 628 | } else { 629 | SimpleDateFormat df = new SimpleDateFormat(format); 630 | return df.format(date); 631 | } 632 | } 633 | 634 | /** 635 | * add by gongtao 636 | *

637 | * 将字符串类型的日期格式 转换为 符合要求的 Date类型的日期格式 638 | *

639 | * 640 | * @param date 641 | * @param format 642 | * @return 643 | */ 644 | public static Date getDate4StrDate(String date, String format) { 645 | if (date == null || date.trim().equals("")) { 646 | return null; 647 | } else { 648 | SimpleDateFormat df = new SimpleDateFormat(format); 649 | try { 650 | return df.parse(date); 651 | } catch (ParseException e) { 652 | return null; 653 | } 654 | } 655 | } 656 | 657 | /** 658 | * add by gongtao 计算指定日期时间之间的时间差 659 | * 660 | * @param beginStr 661 | * 开始日期字符串 662 | * @param endStr 663 | * 结束日期字符串 664 | * @param f 665 | * 时间差的形式0-秒,1-分种,2-小时,3--天 日期时间字符串格式:yyyyMMddHHmmss 666 | * */ 667 | public static int getInterval(String beginStr, String endStr, int f) { 668 | int hours = 0; 669 | try { 670 | Date beginDate = yMd_Hms.parse(beginStr); 671 | Date endDate = yMd_Hms.parse(endStr); 672 | long millisecond = endDate.getTime() - beginDate.getTime(); // 日期相减获取日期差X(单位:毫秒) 673 | /** 674 | * Math.abs((int)(millisecond/1000)); 绝对值 1秒 = 1000毫秒 675 | * millisecond/1000 --> 秒 millisecond/1000*60 - > 分钟 676 | * millisecond/(1000*60*60) -- > 小时 millisecond/(1000*60*60*24) --> 677 | * 天 678 | * */ 679 | switch (f) { 680 | case 0: // second 681 | return (int) (millisecond / 1000); 682 | case 1: // minute 683 | return (int) (millisecond / (1000 * 60)); 684 | case 2: // hour 685 | return (int) (millisecond / (1000 * 60 * 60)); 686 | case 3: // day 687 | return (int) (millisecond / (1000 * 60 * 60 * 24)); 688 | } 689 | } catch (Exception e) { 690 | e.printStackTrace(); 691 | } 692 | return hours; 693 | } 694 | 695 | /** 696 | * add by lipp 697 | *

698 | * 获取起始日期前或后天数的日期 699 | *

700 | * 701 | * @param starttime 702 | * 起始日期 格式:yyyy-MM-dd 703 | * @param days 704 | * @return 705 | * @throws ParseException 706 | */ 707 | public static Date getStartDateInterval(String starttime, int days) { 708 | // 格式化起始时间 yyyyMMdd 709 | Date startDate = null; 710 | try { 711 | startDate = yyyy_MM_dd.parse(starttime); 712 | 713 | } catch (ParseException e) { 714 | e.printStackTrace(); 715 | } 716 | Calendar startTime = Calendar.getInstance(); 717 | startTime.clear(); 718 | startTime.setTime(startDate); 719 | 720 | startTime.add(Calendar.DAY_OF_YEAR, days); 721 | return startTime.getTime(); 722 | } 723 | 724 | /** 725 | * add by lipp 726 | *

727 | * 获取起始日期和结束日期之间的天数 728 | *

729 | * 730 | * @param beginStr 731 | * 起始日期 732 | * @param endStr 733 | * 结束日期 734 | * @param format 735 | * 根据 日期参数的格式,传对应的SimpleDateFormat格式 736 | * @return 天数 737 | */ 738 | public static int getDaysInterval(String beginStr, String endStr, 739 | SimpleDateFormat format) { 740 | 741 | try { 742 | Date beginDate = format.parse(beginStr); 743 | Date endDate = format.parse(endStr); 744 | long millisecond = endDate.getTime() - beginDate.getTime(); // 日期相减获取日期差X(单位:毫秒) 745 | return (int) (millisecond / (1000 * 60 * 60 * 24)); 746 | } catch (ParseException e) { 747 | e.printStackTrace(); 748 | } 749 | return 0; 750 | } 751 | 752 | /** 753 | * 获取本月第一天 754 | * 755 | * @return 756 | */ 757 | public static Date getFristDayOfMonth() { 758 | Calendar calendar = Calendar.getInstance(); 759 | calendar.set(Calendar.DAY_OF_MONTH, 1); 760 | calendar.set(Calendar.HOUR_OF_DAY, 0); 761 | calendar.set(Calendar.SECOND, 0); 762 | calendar.set(Calendar.MINUTE, 0); 763 | return calendar.getTime(); 764 | 765 | } 766 | 767 | /** 768 | * 获取本月最后一天 769 | * 770 | * @return 771 | */ 772 | public static Date getLastDayOfMonth() { 773 | Calendar calendar = Calendar.getInstance(); 774 | calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) + 1); 775 | calendar.set(Calendar.DAY_OF_MONTH, 1); 776 | calendar.set(Calendar.HOUR_OF_DAY, 0); 777 | calendar.set(Calendar.SECOND, 0); 778 | calendar.set(Calendar.MINUTE, 0); 779 | return calendar.getTime(); 780 | 781 | } 782 | 783 | /** 784 | * 获得本周一的日期 785 | * 786 | * @return 787 | * @throws ParseException 788 | */ 789 | /* 790 | * public static Date getMondayOFWeek() throws ParseException { int 791 | * mondayPlus = getMondayPlus(); GregorianCalendar currentDate = new 792 | * GregorianCalendar(); currentDate.add(Calendar.DATE, mondayPlus); Date 793 | * monday = currentDate.getTime(); String dateStr = getDateTime_I(monday); 794 | * StringBuffer sb = new StringBuffer(dateStr); 795 | * sb.append(" ").append("00:00:00"); return 796 | * parseDateStrToDate(sb.toString()); } 797 | */ 798 | 799 | /** 800 | * 获得本周星期日的日期 801 | * 802 | * @return 803 | * @throws ParseException 804 | */ 805 | /* 806 | * public static Date getCurrentWeekday() throws ParseException { int 807 | * mondayPlus = getMondayPlus(); GregorianCalendar currentDate = new 808 | * GregorianCalendar(); currentDate.add(Calendar.DATE, mondayPlus + 6); Date 809 | * monday = currentDate.getTime(); String dateStr = getDateTime_I(monday); 810 | * StringBuffer sb = new StringBuffer(dateStr); 811 | * sb.append(" ").append("00:00:00"); return 812 | * parseDateStrToDate(sb.toString()); } 813 | */ 814 | 815 | /** 816 | * 字符串时间格式转换为 Date 817 | * 818 | * @param date 819 | * 此格式 yyyy-MM-dd HH:mm:ss 820 | * @return 821 | * @throws ParseException 822 | */ 823 | /* 824 | * public static Date parseDateStrToDate(String date) throws ParseException{ 825 | * Date date_time = null; if(!StringUtil.isEmpty(date)){ date_time = 826 | * yMd_Hms.parse(date); } return date_time; } 827 | */ 828 | /** 829 | * 字符串时间格式转换为 Date 830 | * 831 | * @param date 832 | * 此格式 yyyy-MM-dd 833 | * @return 834 | * @throws ParseException 835 | */ 836 | /* 837 | * public static Date parseDateFromStr(String date) throws ParseException{ 838 | * Date date_time = null; if(!StringUtil.isEmpty(date)){ date_time = 839 | * yyyy_MM_dd.parse(date); } return date_time; } 840 | */ 841 | 842 | public static int getMondayPlus() { 843 | Calendar cd = Calendar.getInstance(); 844 | // 因为按中国礼拜一作为第一天所以这里减1 845 | int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK) - 1; 846 | if (dayOfWeek == 1) { 847 | return 0; 848 | } else if (dayOfWeek == 0) { 849 | return 1 - 7; 850 | } else { 851 | return 1 - dayOfWeek; 852 | } 853 | } 854 | 855 | /** 856 | * 857 | * @param beginDate 858 | * @param endDate 859 | * @param f 860 | * 时间差的形式0:秒,1:分种,2:小时,3:天 861 | * @return 862 | */ 863 | public static int getDifferenceNum(Date beginDate, Date endDate, int f) { 864 | int result = 0; 865 | if (beginDate == null || endDate == null) { 866 | return 0; 867 | } 868 | try { 869 | // 日期相减获取日期差X(单位:毫秒) 870 | long millisecond = endDate.getTime() - beginDate.getTime(); 871 | /** 872 | * Math.abs((int)(millisecond/1000)); 绝对值 1秒 = 1000毫秒 873 | * millisecond/1000 --> 秒 millisecond/1000*60 - > 分钟 874 | * millisecond/(1000*60*60) -- > 小时 millisecond/(1000*60*60*24) --> 875 | * 天 876 | * */ 877 | switch (f) { 878 | case 0: // second 879 | return (int) (millisecond / 1000); 880 | case 1: // minute 881 | return (int) (millisecond / (1000 * 60)); 882 | case 2: // hour 883 | return (int) (millisecond / (1000 * 60 * 60)); 884 | case 3: // day 885 | return (int) (millisecond / (1000 * 60 * 60 * 24)); 886 | } 887 | } catch (Exception e) { 888 | e.printStackTrace(); 889 | } 890 | return result; 891 | } 892 | 893 | /** 894 | * 两个时间间的时间戳计算函数 895 | * 896 | * @param beginDate 897 | * @param endDate 898 | * @param f 899 | * 时间差的形式0:秒,1:分种,2:小时,3:天 900 | * @return long 秒 901 | */ 902 | public static long getDifference(Date beginDate, Date endDate, int f) { 903 | long result = 0; 904 | if (beginDate == null || endDate == null) { 905 | return 0; 906 | } 907 | try { 908 | // 日期相减获取日期差X(单位:毫秒) 909 | long millisecond = endDate.getTime() - beginDate.getTime(); 910 | /** 911 | * Math.abs((int)(millisecond/1000)); 绝对值 1秒 = 1000毫秒 912 | * millisecond/1000 --> 秒 millisecond/1000*60 - > 分钟 913 | * millisecond/(1000*60*60) -- > 小时 millisecond/(1000*60*60*24) --> 914 | * 天 915 | * */ 916 | switch (f) { 917 | case 0: // second 918 | return (millisecond / 1000); 919 | case 1: // minute 920 | return (millisecond / (1000 * 60)); 921 | case 2: // hour 922 | return (millisecond / (1000 * 60 * 60)); 923 | case 3: // day 924 | return (millisecond / (1000 * 60 * 60 * 24)); 925 | } 926 | } catch (Exception e) { 927 | e.printStackTrace(); 928 | } 929 | return result; 930 | } 931 | 932 | /** 933 | *

934 | * 比较两个日期的大小,精确到秒 935 | *

936 | * 937 | * @param d1 938 | * @param d2 939 | * @author lipp@icloud-edu.com 940 | * @date 2014-06-03 941 | * @return 返回一个long类型的整数,若大于0表示第一个日期晚于第二个日期,小于0表示第一个日期早于第二个日期,否则相等 942 | */ 943 | public static long compareEachOther(Date d1, Date d2) { 944 | if (d1 == null || d2 == null) 945 | return -1; 946 | String d1Str = d1.getTime() + ""; 947 | String d2Str = d2.getTime() + ""; 948 | int l1 = d1Str.length(); 949 | int l2 = d2Str.length(); 950 | d1Str = d1Str.substring(0, l1 - 3) + "000"; 951 | d2Str = d2Str.substring(0, l2 - 3) + "000"; 952 | // System.out.println(d1Str + " " + d2Str); 953 | long long1 = Long.parseLong(d1Str); 954 | long long2 = Long.parseLong(d2Str); 955 | return long1 - long2; 956 | } 957 | 958 | public static Date getPreYearStartTime() { 959 | Calendar cal = Calendar.getInstance(); 960 | cal.add(Calendar.YEAR, -1); 961 | cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), 962 | cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0); 963 | cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.YEAR)); 964 | return cal.getTime(); 965 | } 966 | 967 | public static Date getCurrentYearStartTime() { 968 | Calendar cal = Calendar.getInstance(); 969 | cal.set(cal.get(Calendar.YEAR), cal.get(Calendar.MONDAY), 970 | cal.get(Calendar.DAY_OF_MONTH), 0, 0, 0); 971 | cal.set(Calendar.DAY_OF_MONTH, cal.getActualMinimum(Calendar.YEAR)); 972 | return cal.getTime(); 973 | } 974 | 975 | /** 976 | * 当前季度的结束时间,即2012-03-31 23:59:59 977 | * 978 | * @return 979 | */ 980 | public static Date getCurrentQuarterEndTime() { 981 | Calendar cal = Calendar.getInstance(); 982 | cal.setTime(getCurrentQuarterStartTime()); 983 | cal.add(Calendar.MONTH, 3); 984 | return cal.getTime(); 985 | } 986 | 987 | /** 988 | * 前季度的结束时间,即2012-03-31 23:59:59 989 | * 990 | * @return 991 | */ 992 | public static Date getPreQuarterEndTime() { 993 | Calendar cal = Calendar.getInstance(); 994 | cal.setTime(getPreQuarterStartTime()); 995 | cal.add(Calendar.MONTH, 3); 996 | return cal.getTime(); 997 | } 998 | 999 | /** 1000 | * 当前季度的开始时间,即2012-03-31 23:59:59 1001 | * 1002 | * @return 1003 | */ 1004 | public static Date getCurrentQuarterStartTime() { 1005 | Calendar c = Calendar.getInstance(); 1006 | // c.add(Calendar.MONTH, -3); 1007 | int currentMonth = c.get(Calendar.MONTH) + 1; 1008 | System.out.println("currentMoth" + currentMonth); 1009 | SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 1010 | SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd"); 1011 | Date now = null; 1012 | try { 1013 | if (currentMonth >= 1 && currentMonth <= 3) 1014 | c.set(Calendar.MONTH, 0); 1015 | else if (currentMonth >= 4 && currentMonth <= 6) 1016 | c.set(Calendar.MONTH, 3); 1017 | else if (currentMonth >= 7 && currentMonth <= 9) { 1018 | c.set(Calendar.MONTH, 6); 1019 | System.out.println(new SimpleDateFormat("yyyyMM").format(c 1020 | .getTime())); 1021 | } else if (currentMonth >= 10 && currentMonth <= 12) 1022 | c.set(Calendar.MONTH, 9); 1023 | c.set(Calendar.DATE, 1); 1024 | now = longSdf.parse(shortSdf.format(c.getTime()) + " 00:00:00"); 1025 | } catch (Exception e) { 1026 | e.printStackTrace(); 1027 | } 1028 | return now; 1029 | } 1030 | 1031 | /** 1032 | * 前季度的开始时间,即2012-03-31 23:59:59 1033 | * 1034 | * @return 1035 | */ 1036 | public static Date getPreQuarterStartTime() { 1037 | Calendar c = Calendar.getInstance(); 1038 | c.add(Calendar.MONTH, -3); 1039 | int currentMonth = c.get(Calendar.MONTH) + 1; 1040 | System.out.println("currentMoth" + currentMonth); 1041 | SimpleDateFormat longSdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 1042 | SimpleDateFormat shortSdf = new SimpleDateFormat("yyyy-MM-dd"); 1043 | Date now = null; 1044 | try { 1045 | if (currentMonth >= 1 && currentMonth <= 3) 1046 | c.set(Calendar.MONTH, 0); 1047 | else if (currentMonth >= 4 && currentMonth <= 6) 1048 | c.set(Calendar.MONTH, 3); 1049 | else if (currentMonth >= 7 && currentMonth <= 9) { 1050 | c.set(Calendar.MONTH, 6); 1051 | System.out.println(new SimpleDateFormat("yyyyMM").format(c 1052 | .getTime())); 1053 | } else if (currentMonth >= 10 && currentMonth <= 12) 1054 | c.set(Calendar.MONTH, 9); 1055 | c.set(Calendar.DATE, 1); 1056 | now = longSdf.parse(shortSdf.format(c.getTime()) + " 00:00:00"); 1057 | } catch (Exception e) { 1058 | e.printStackTrace(); 1059 | } 1060 | return now; 1061 | } 1062 | 1063 | /** 1064 | * 根据指定日期,来运算加减乘除 1065 | * 1066 | * @param date 1067 | * @param format 1068 | * @param value 1069 | * add(new Date(),"yyyy-MM-dd HH:mm:ss",-1 * 1 * 60 * 60 * 1000); 1070 | */ 1071 | public static String add(Date date, String format, long value) { 1072 | SimpleDateFormat df = new SimpleDateFormat(format); 1073 | long newValue = date.getTime() + value; 1074 | return df.format(new Date(newValue)); 1075 | } 1076 | 1077 | public static long addLong(Date date, String format, long value) { 1078 | SimpleDateFormat df = new SimpleDateFormat(format); 1079 | long newValue = date.getTime() + value; 1080 | return newValue; 1081 | } 1082 | 1083 | /** 1084 | * 计算时差 根据 long 返回时间点 1085 | * 1086 | * @param millisecond 1087 | * @return string 0天0时11分55秒 1088 | */ 1089 | public static String parseMillisecone(long millisecond) { 1090 | String time = null; 1091 | try { 1092 | long yushu_day = millisecond % (1000 * 60 * 60 * 24); 1093 | long yushu_hour = (millisecond % (1000 * 60 * 60 * 24)) 1094 | % (1000 * 60 * 60); 1095 | long yushu_minute = millisecond % (1000 * 60 * 60 * 24) 1096 | % (1000 * 60 * 60) % (1000 * 60); 1097 | @SuppressWarnings("unused") 1098 | long yushu_second = millisecond % (1000 * 60 * 60 * 24) 1099 | % (1000 * 60 * 60) % (1000 * 60) % 1000; 1100 | if (yushu_day == 0) { 1101 | return (millisecond / (1000 * 60 * 60 * 24)) + "天"; 1102 | } else { 1103 | if (yushu_hour == 0) { 1104 | return (millisecond / (1000 * 60 * 60 * 24)) + "天" 1105 | + (yushu_day / (1000 * 60 * 60)) + "时"; 1106 | } else { 1107 | if (yushu_minute == 0) { 1108 | return (millisecond / (1000 * 60 * 60 * 24)) + "天" 1109 | + (yushu_day / (1000 * 60 * 60)) + "时" 1110 | + (yushu_hour / (1000 * 60)) + "分"; 1111 | } else { 1112 | return (millisecond / (1000 * 60 * 60 * 24)) + "天" 1113 | + (yushu_day / (1000 * 60 * 60)) + "时" 1114 | + (yushu_hour / (1000 * 60)) + "分" 1115 | + (yushu_minute / 1000) + "秒"; 1116 | 1117 | } 1118 | 1119 | } 1120 | 1121 | } 1122 | 1123 | } catch (Exception e) { 1124 | e.printStackTrace(); 1125 | } 1126 | return time; 1127 | } 1128 | 1129 | public static void main(String[] args) throws ParseException { 1130 | // 获取指定long型的时间 1131 | System.out.println(parseMillisecone(436765000L)); 1132 | ; 1133 | // 获取时间差的秒数 1134 | long diff = getDifference(new Date(), new SimpleDateFormat( 1135 | "yyyy-MM-dd HH:mm:ss").parse("2016-12-10 00:00:00"), 0); 1136 | System.out.println(getDifference(new Date(), new SimpleDateFormat( 1137 | "yyyy-MM-dd HH:mm:ss").parse("2016-12-10 00:00:00"), 0)); 1138 | System.out.println("时间:" + parseMillisecone(diff)); 1139 | System.out.println("时间:" + parseMillisecone(diff * 1000)); 1140 | } 1141 | } 1142 | -------------------------------------------------------------------------------- /src/main/java/com/scienjus/utils/MD5Utils.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.utils; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.security.SecureRandom; 7 | import java.util.Arrays; 8 | 9 | /** 10 | * MD5加密解密及字符串对比工具类 11 | * @author jacob_ye 12 | * http://www.blog.csdn.net/zranye 13 | * 盐加密和普通加密 14 | */ 15 | public class MD5Utils { 16 | private final static String HEX_NUMS_STR = "0123456789ABCDEF"; 17 | private final static Integer SALT_LENGTH = 15; 18 | 19 | /** 20 | * 将16进制字符串转换成数组 21 | * 22 | * @return byte[] 23 | * @author jacob 24 | * */ 25 | public static byte[] hexStringToByte(String hex) { 26 | /* len为什么是hex.length() / 2 ? 27 | * 首先,hex是一个字符串,里面的内容是像16进制那样的char数组 28 | * 用2个16进制数字可以表示1个byte,所以要求得这些char[]可以转化成什么样的byte[],首先可以确定的就是长度为这个char[]的一半 29 | */ 30 | int len = (hex.length() / 2); 31 | byte[] result = new byte[len]; 32 | char[] hexChars = hex.toCharArray(); 33 | for (int i = 0; i < len; i++) { 34 | int pos = i * 2; 35 | result[i] = (byte) (HEX_NUMS_STR.indexOf(hexChars[pos]) << 4 | HEX_NUMS_STR 36 | .indexOf(hexChars[pos + 1])); 37 | } 38 | return result; 39 | } 40 | 41 | /** 42 | * 将数组转换成16进制字符串 43 | * 44 | * @return String 45 | * @author jacob 46 | * 47 | * */ 48 | public static String byteToHexString(byte[] salt){ 49 | StringBuffer hexString = new StringBuffer(); 50 | for (int i = 0; i < salt.length; i++) { 51 | String hex = Integer.toHexString(salt[i] & 0xFF); 52 | if(hex.length() == 1){ 53 | hex = '0' + hex; 54 | } 55 | hexString.append(hex.toUpperCase()); 56 | } 57 | return hexString.toString(); 58 | } 59 | 60 | /** 61 | * 密码验证 62 | * @param passwd 用户输入密码 63 | * @param dbPasswd 数据库保存的密码 64 | * @return 65 | * @throws NoSuchAlgorithmException 66 | * @throws UnsupportedEncodingException 67 | */ 68 | public static boolean validPasswd(String passwd, String dbPasswd) 69 | throws NoSuchAlgorithmException, UnsupportedEncodingException{ 70 | byte[] pwIndb = hexStringToByte(dbPasswd); 71 | //定义salt 72 | byte[] salt = new byte[SALT_LENGTH]; 73 | System.arraycopy(pwIndb, 0, salt, 0, SALT_LENGTH); 74 | //创建消息摘要对象 75 | MessageDigest md = MessageDigest.getInstance("MD5"); 76 | //将盐数据传入消息摘要对象 77 | md.update(salt); 78 | md.update(passwd.getBytes("UTF-8")); 79 | byte[] digest = md.digest(); 80 | //声明一个对象接收数据库中的口令消息摘要 81 | byte[] digestIndb = new byte[pwIndb.length - SALT_LENGTH]; 82 | //获得数据库中口令的摘要 83 | System.arraycopy(pwIndb, SALT_LENGTH, digestIndb, 0,digestIndb.length); 84 | //比较根据输入口令生成的消息摘要和数据库中的口令摘要是否相同 85 | if(Arrays.equals(digest, digestIndb)){ 86 | //口令匹配相同 87 | return true; 88 | }else{ 89 | return false; 90 | } 91 | } 92 | 93 | 94 | 95 | /** 96 | * 获得md5之后的16进制字符 +盐值加密 97 | * @param passwd 用户输入密码字符 98 | * @return String md5加密后密码字符 99 | * @throws NoSuchAlgorithmException 100 | * @throws UnsupportedEncodingException 101 | */ 102 | public static String getEncryptedPwd(String passwd) 103 | throws NoSuchAlgorithmException, UnsupportedEncodingException{ 104 | //拿到一个随机数组,作为盐 105 | byte[] pwd = null; 106 | SecureRandom sc= new SecureRandom(); 107 | byte[] salt = new byte[SALT_LENGTH]; 108 | sc.nextBytes(salt); 109 | 110 | //声明摘要对象,并生成 111 | MessageDigest md = MessageDigest.getInstance("MD5"); 112 | md.update(salt); 113 | md.update(passwd.getBytes("UTF-8")); 114 | byte[] digest = md.digest(); 115 | 116 | pwd = new byte[salt.length + digest.length]; 117 | System.arraycopy(salt, 0, pwd, 0, SALT_LENGTH); 118 | System.arraycopy(digest, 0, pwd, SALT_LENGTH, digest.length); 119 | return byteToHexString(pwd); 120 | } 121 | 122 | 123 | /** 124 | * 任意一种文字加密为md5(不可逆算法) +不加盐加密 125 | * Can convert a file to MD5 126 | * @param text 127 | * @return md5 128 | */ 129 | public static String encode(String text){ 130 | try { 131 | MessageDigest digest = MessageDigest.getInstance("md5"); 132 | byte[] buffer = digest.digest(text.getBytes()); 133 | // byte -128 ---- 127 134 | StringBuffer sb = new StringBuffer(); 135 | for (byte b : buffer) { 136 | int a = b & 0xff; 137 | // Log.d(TAG, "" + a); 138 | String hex = Integer.toHexString(a); 139 | 140 | if (hex.length() == 1) { 141 | hex = 0 + hex; 142 | } 143 | sb.append(hex); 144 | } 145 | return sb.toString(); 146 | } catch (NoSuchAlgorithmException e) { 147 | e.printStackTrace(); 148 | } 149 | return null; 150 | } 151 | 152 | public static void main(String[] args) { 153 | System.out.println(encode("123456")); 154 | try { 155 | String pwd=getEncryptedPwd("123456"); 156 | System.out.println(pwd); 157 | System.out.println(validPasswd("123456", "9C8C6E5E844BE0E337CECADF2ED6F71E692B8943C5F2AB248194232D7997EB")); 158 | } catch (NoSuchAlgorithmException e) { 159 | e.printStackTrace(); 160 | } catch (UnsupportedEncodingException e) { 161 | e.printStackTrace(); 162 | } 163 | } 164 | } -------------------------------------------------------------------------------- /src/main/java/com/scienjus/utils/RSAUtils.java: -------------------------------------------------------------------------------- 1 | package com.scienjus.utils; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.security.Key; 5 | import java.security.KeyFactory; 6 | import java.security.KeyPair; 7 | import java.security.KeyPairGenerator; 8 | import java.security.PrivateKey; 9 | import java.security.PublicKey; 10 | import java.security.Signature; 11 | import java.security.interfaces.RSAPrivateKey; 12 | import java.security.interfaces.RSAPublicKey; 13 | import java.security.spec.PKCS8EncodedKeySpec; 14 | import java.security.spec.X509EncodedKeySpec; 15 | import java.util.HashMap; 16 | import java.util.Map; 17 | 18 | import javax.crypto.Cipher; 19 | 20 | /** 21 | *

22 | * RSA公钥/私钥/签名工具包 23 | *

24 | *

25 | * 罗纳德·李维斯特(Ron [R]ivest)、阿迪·萨莫尔(Adi [S]hamir)和伦纳德·阿德曼(Leonard [A]dleman) 26 | *

27 | *

28 | * 字符串格式的密钥在未在特殊说明情况下都为BASE64编码格式
29 | * 由于非对称加密速度极其缓慢,一般文件不使用它来加密而是使用对称加密,
30 | * 非对称加密算法可以用来对对称加密的密钥加密,这样保证密钥的安全也就保证了数据的安全 31 | *

32 | * 33 | * @author IceWee 34 | * @date 2012-4-26 35 | * @version 1.0 36 | */ 37 | public class RSAUtils { 38 | 39 | /** 40 | * 加密算法RSA 41 | */ 42 | public static final String KEY_ALGORITHM = "RSA"; 43 | 44 | /** 45 | * 签名算法 46 | */ 47 | public static final String SIGNATURE_ALGORITHM = "MD5withRSA"; 48 | 49 | /** 50 | * 获取公钥的key 51 | */ 52 | private static final String PUBLIC_KEY = "RSAPublicKey"; 53 | 54 | /** 55 | * 获取私钥的key 56 | */ 57 | private static final String PRIVATE_KEY = "RSAPrivateKey"; 58 | 59 | /** 60 | * RSA最大加密明文大小 61 | */ 62 | private static final int MAX_ENCRYPT_BLOCK = 117; 63 | 64 | /** 65 | * RSA最大解密密文大小 66 | */ 67 | private static final int MAX_DECRYPT_BLOCK = 128; 68 | 69 | /** 70 | *

71 | * 生成密钥对(公钥和私钥) 72 | *

73 | * 74 | * @return 75 | * @throws Exception 76 | */ 77 | public static Map genKeyPair() throws Exception { 78 | KeyPairGenerator keyPairGen = KeyPairGenerator 79 | .getInstance(KEY_ALGORITHM); 80 | keyPairGen.initialize(1024); 81 | KeyPair keyPair = keyPairGen.generateKeyPair(); 82 | RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic(); 83 | RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate(); 84 | Map keyMap = new HashMap(2); 85 | keyMap.put(PUBLIC_KEY, publicKey); 86 | keyMap.put(PRIVATE_KEY, privateKey); 87 | return keyMap; 88 | } 89 | 90 | /** 91 | *

92 | * 用私钥对信息生成数字签名 93 | *

94 | * 95 | * @param data 96 | * 已加密数据 97 | * @param privateKey 98 | * 私钥(BASE64编码) 99 | * 100 | * @return 101 | * @throws Exception 102 | */ 103 | public static String sign(byte[] data, String privateKey) throws Exception { 104 | byte[] keyBytes = Base64Utils.decode(privateKey); 105 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 106 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 107 | PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec); 108 | Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 109 | signature.initSign(privateK); 110 | signature.update(data); 111 | return Base64Utils.encode(signature.sign()); 112 | } 113 | 114 | /** 115 | *

116 | * 校验数字签名 117 | *

118 | * 119 | * @param data 120 | * 已加密数据 121 | * @param publicKey 122 | * 公钥(BASE64编码) 123 | * @param sign 124 | * 数字签名 125 | * 126 | * @return 127 | * @throws Exception 128 | * 129 | */ 130 | public static boolean verify(byte[] data, String publicKey, String sign) 131 | throws Exception { 132 | byte[] keyBytes = Base64Utils.decode(publicKey); 133 | X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); 134 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 135 | PublicKey publicK = keyFactory.generatePublic(keySpec); 136 | Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM); 137 | signature.initVerify(publicK); 138 | signature.update(data); 139 | return signature.verify(Base64Utils.decode(sign)); 140 | } 141 | 142 | /** 143 | *

144 | * 私钥解密 145 | *

146 | * 147 | * @param encryptedData 148 | * 已加密数据 149 | * @param privateKey 150 | * 私钥(BASE64编码) 151 | * @return 152 | * @throws Exception 153 | */ 154 | public static byte[] decryptByPrivateKey(byte[] encryptedData, 155 | String privateKey) throws Exception { 156 | byte[] keyBytes = Base64Utils.decode(privateKey); 157 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 158 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 159 | Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 160 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 161 | cipher.init(Cipher.DECRYPT_MODE, privateK); 162 | int inputLen = encryptedData.length; 163 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 164 | int offSet = 0; 165 | byte[] cache; 166 | int i = 0; 167 | // 对数据分段解密 168 | while (inputLen - offSet > 0) { 169 | if (inputLen - offSet > MAX_DECRYPT_BLOCK) { 170 | cache = cipher 171 | .doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); 172 | } else { 173 | cache = cipher 174 | .doFinal(encryptedData, offSet, inputLen - offSet); 175 | } 176 | out.write(cache, 0, cache.length); 177 | i++; 178 | offSet = i * MAX_DECRYPT_BLOCK; 179 | } 180 | byte[] decryptedData = out.toByteArray(); 181 | out.close(); 182 | return decryptedData; 183 | } 184 | 185 | /** 186 | *

187 | * 公钥解密 188 | *

189 | * 190 | * @param encryptedData 191 | * 已加密数据 192 | * @param publicKey 193 | * 公钥(BASE64编码) 194 | * @return 195 | * @throws Exception 196 | */ 197 | public static byte[] decryptByPublicKey(byte[] encryptedData, 198 | String publicKey) throws Exception { 199 | byte[] keyBytes = Base64Utils.decode(publicKey); 200 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 201 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 202 | Key publicK = keyFactory.generatePublic(x509KeySpec); 203 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 204 | cipher.init(Cipher.DECRYPT_MODE, publicK); 205 | int inputLen = encryptedData.length; 206 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 207 | int offSet = 0; 208 | byte[] cache; 209 | int i = 0; 210 | // 对数据分段解密 211 | while (inputLen - offSet > 0) { 212 | if (inputLen - offSet > MAX_DECRYPT_BLOCK) { 213 | cache = cipher 214 | .doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK); 215 | } else { 216 | cache = cipher 217 | .doFinal(encryptedData, offSet, inputLen - offSet); 218 | } 219 | out.write(cache, 0, cache.length); 220 | i++; 221 | offSet = i * MAX_DECRYPT_BLOCK; 222 | } 223 | byte[] decryptedData = out.toByteArray(); 224 | out.close(); 225 | return decryptedData; 226 | } 227 | 228 | /** 229 | *

230 | * 公钥加密 231 | *

232 | * 233 | * @param data 234 | * 源数据 235 | * @param publicKey 236 | * 公钥(BASE64编码) 237 | * @return 238 | * @throws Exception 239 | */ 240 | public static byte[] encryptByPublicKey(byte[] data, String publicKey) 241 | throws Exception { 242 | byte[] keyBytes = Base64Utils.decode(publicKey); 243 | X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); 244 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 245 | Key publicK = keyFactory.generatePublic(x509KeySpec); 246 | // 对数据加密 247 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 248 | cipher.init(Cipher.ENCRYPT_MODE, publicK); 249 | int inputLen = data.length; 250 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 251 | int offSet = 0; 252 | byte[] cache; 253 | int i = 0; 254 | // 对数据分段加密 255 | while (inputLen - offSet > 0) { 256 | if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 257 | cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 258 | } else { 259 | cache = cipher.doFinal(data, offSet, inputLen - offSet); 260 | } 261 | out.write(cache, 0, cache.length); 262 | i++; 263 | offSet = i * MAX_ENCRYPT_BLOCK; 264 | } 265 | byte[] encryptedData = out.toByteArray(); 266 | out.close(); 267 | return encryptedData; 268 | } 269 | 270 | /** 271 | *

272 | * 私钥加密 273 | *

274 | * 275 | * @param data 276 | * 源数据 277 | * @param privateKey 278 | * 私钥(BASE64编码) 279 | * @return 280 | * @throws Exception 281 | */ 282 | public static byte[] encryptByPrivateKey(byte[] data, String privateKey) 283 | throws Exception { 284 | byte[] keyBytes = Base64Utils.decode(privateKey); 285 | PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); 286 | KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); 287 | Key privateK = keyFactory.generatePrivate(pkcs8KeySpec); 288 | Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); 289 | cipher.init(Cipher.ENCRYPT_MODE, privateK); 290 | int inputLen = data.length; 291 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 292 | int offSet = 0; 293 | byte[] cache; 294 | int i = 0; 295 | // 对数据分段加密 296 | while (inputLen - offSet > 0) { 297 | if (inputLen - offSet > MAX_ENCRYPT_BLOCK) { 298 | cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK); 299 | } else { 300 | cache = cipher.doFinal(data, offSet, inputLen - offSet); 301 | } 302 | out.write(cache, 0, cache.length); 303 | i++; 304 | offSet = i * MAX_ENCRYPT_BLOCK; 305 | } 306 | byte[] encryptedData = out.toByteArray(); 307 | out.close(); 308 | return encryptedData; 309 | } 310 | 311 | /** 312 | *

313 | * 获取私钥 314 | *

315 | * 316 | * @param keyMap 317 | * 密钥对 318 | * @return 319 | * @throws Exception 320 | */ 321 | public static String getPrivateKey(Map keyMap) 322 | throws Exception { 323 | Key key = (Key) keyMap.get(PRIVATE_KEY); 324 | return Base64Utils.encode(key.getEncoded()); 325 | } 326 | 327 | /** 328 | *

329 | * 获取公钥 330 | *

331 | * 332 | * @param keyMap 333 | * 密钥对 334 | * @return 335 | * @throws Exception 336 | */ 337 | public static String getPublicKey(Map keyMap) 338 | throws Exception { 339 | Key key = (Key) keyMap.get(PUBLIC_KEY); 340 | return Base64Utils.encode(key.getEncoded()); 341 | } 342 | 343 | } -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | #MySQL 2 | spring.datasource.url=jdbc:mysql://127.0.0.1:3306/demo_token?useUnicode=true&autoReconnect=true&failOverReadOnly=false&zeroDateTimeBehavior=round&autoReconnect=true 3 | spring.datasource.username=root 4 | spring.datasource.password=123456 5 | #指定连接池等待连接返回的最大等待时间,毫秒单位.两天 6 | spring.datasource.max-wait=172800000 7 | 8 | # the servlet path, defaults to '/' 9 | server.port=8080 10 | # session timeout in seconds 11 | server.session-timeout=3600000 12 | #项目根路径 13 | server.context-path=/spring-restful-authorization 14 | #server.servlet-path=/spring-restful-authorization 15 | # character encoding to use for URL decoding 16 | #server.tomcat.uri-encoding=UTF-8 17 | 18 | #Redis 19 | spring.redis.host=127.0.0.1 20 | # 没有密码就不填写 21 | spring.redis.password= 22 | spring.redis.port=6379 23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/init.sql: -------------------------------------------------------------------------------- 1 | create table user_ ( 2 | username_ varchar(20) unique not null, 3 | password_ varchar(20) not null, 4 | id_ int unsigned auto_increment, 5 | nickname_ varchar(20) not null, 6 | primary key(id_) 7 | ); 8 | 9 | insert into user_ (username_, password_, nickname_) values ('admin', 'password', 'admin' ); -------------------------------------------------------------------------------- /src/main/resources/public/css/reset.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ v2.0 | 20110126 */ 2 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, 3 | blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, 4 | em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, 5 | b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, 6 | table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, 7 | details, embed, figure, figcaption, footer, header, hgroup, menu, nav, 8 | output, ruby, section, summary, time, mark, audio, video { 9 | margin: 0; 10 | padding: 0; 11 | border: 0; 12 | font-size: 100%; 13 | font: inherit; 14 | vertical-align: baseline; 15 | } 16 | /* HTML5 display-role reset for older browsers */ 17 | article, aside, details, figcaption, figure, footer, header, hgroup, 18 | menu, nav, section { 19 | display: block; 20 | } 21 | 22 | body { 23 | line-height: 1; 24 | } 25 | 26 | ol, ul { 27 | list-style: none; 28 | } 29 | 30 | blockquote, q { 31 | quotes: none; 32 | } 33 | 34 | blockquote:before, blockquote:after, q:before, q:after { 35 | content: ''; 36 | content: none; 37 | } 38 | 39 | table { 40 | border-collapse: collapse; 41 | border-spacing: 0; 42 | } -------------------------------------------------------------------------------- /src/main/resources/public/css/style.css: -------------------------------------------------------------------------------- 1 | .swagger-section #header a#logo { 2 | font-size: 1.5em; 3 | font-weight: bold; 4 | text-decoration: none; 5 | background: transparent url(../images/logo.png) no-repeat left center; 6 | padding: 20px 0 20px 40px; 7 | } 8 | #text-head { 9 | font-size: 80px; 10 | font-family: 'Roboto', sans-serif; 11 | color: #ffffff; 12 | float: right; 13 | margin-right: 20%; 14 | } 15 | .navbar-fixed-top .navbar-nav { 16 | height: auto; 17 | } 18 | .navbar-fixed-top .navbar-brand { 19 | height: auto; 20 | } 21 | .navbar-header { 22 | height: auto; 23 | } 24 | .navbar-inverse { 25 | background-color: #000; 26 | border-color: #000; 27 | } 28 | #navbar-brand { 29 | margin-left: 20%; 30 | } 31 | .navtext { 32 | font-size: 10px; 33 | } 34 | .h1, 35 | h1 { 36 | font-size: 60px; 37 | } 38 | .navbar-default .navbar-header .navbar-brand { 39 | color: #a2dfee; 40 | } 41 | /* tag titles */ 42 | .swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a { 43 | color: #393939; 44 | font-family: 'Arvo', serif; 45 | font-size: 1.5em; 46 | } 47 | .swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 a:hover { 48 | color: black; 49 | } 50 | .swagger-section .swagger-ui-wrap ul#resources li.resource div.heading h2 { 51 | color: #525252; 52 | padding-left: 0px; 53 | display: block; 54 | clear: none; 55 | float: left; 56 | font-family: 'Arvo', serif; 57 | font-weight: bold; 58 | } 59 | .navbar-default .navbar-collapse, 60 | .navbar-default .navbar-form { 61 | border-color: #0A0A0A; 62 | } 63 | .container1 { 64 | width: 1500px; 65 | margin: auto; 66 | margin-top: 0; 67 | background-image: url('../images/shield.png'); 68 | background-repeat: no-repeat; 69 | background-position: -40px -20px; 70 | margin-bottom: 210px; 71 | } 72 | .container-inner { 73 | width: 1200px; 74 | margin: auto; 75 | background-color: rgba(223, 227, 228, 0.75); 76 | padding-bottom: 40px; 77 | padding-top: 40px; 78 | border-radius: 15px; 79 | } 80 | .header-content { 81 | padding: 0; 82 | width: 1000px; 83 | } 84 | .title1 { 85 | font-size: 80px; 86 | font-family: 'Vollkorn', serif; 87 | color: #404040; 88 | text-align: center; 89 | padding-top: 40px; 90 | padding-bottom: 100px; 91 | } 92 | #icon { 93 | margin-top: -18px; 94 | } 95 | .subtext { 96 | font-size: 25px; 97 | font-style: italic; 98 | color: #08b; 99 | text-align: right; 100 | padding-right: 250px; 101 | } 102 | .bg-primary { 103 | background-color: #00468b; 104 | } 105 | .navbar-default .nav > li > a, 106 | .navbar-default .nav > li > a:focus { 107 | color: #08b; 108 | } 109 | .navbar-default .nav > li > a, 110 | .navbar-default .nav > li > a:hover { 111 | color: #08b; 112 | } 113 | .navbar-default .nav > li > a, 114 | .navbar-default .nav > li > a:focus:hover { 115 | color: #08b; 116 | } 117 | .text-faded { 118 | font-size: 25px; 119 | font-family: 'Vollkorn', serif; 120 | } 121 | .section-heading { 122 | font-family: 'Vollkorn', serif; 123 | font-size: 45px; 124 | padding-bottom: 10px; 125 | } 126 | hr { 127 | border-color: #00468b; 128 | padding-bottom: 10px; 129 | } 130 | .description { 131 | margin-top: 20px; 132 | padding-bottom: 200px; 133 | } 134 | .description li { 135 | font-family: 'Vollkorn', serif; 136 | font-size: 25px; 137 | color: #525252; 138 | margin-left: 28%; 139 | padding-top: 5px; 140 | } 141 | .gap { 142 | margin-top: 200px; 143 | } 144 | .troubleshootingtext { 145 | color: rgba(255, 255, 255, 0.7); 146 | padding-left: 30%; 147 | } 148 | .troubleshootingtext li { 149 | list-style-type: circle; 150 | font-size: 25px; 151 | padding-bottom: 5px; 152 | } 153 | .overlay { 154 | position: absolute; 155 | top: 0; 156 | left: 0; 157 | width: 100%; 158 | height: 100%; 159 | z-index: 1000; 160 | } 161 | .block.response_body.json:hover { 162 | cursor: pointer; 163 | } 164 | .backdrop { 165 | color: blue; 166 | } 167 | #myModal { 168 | height: 100%; 169 | } 170 | .modal-backdrop { 171 | bottom: 0; 172 | position: fixed; 173 | } 174 | .curl { 175 | padding: 10px; 176 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 177 | font-size: 0.9em; 178 | max-height: 400px; 179 | margin-top: 5px; 180 | overflow-y: auto; 181 | background-color: #fcf6db; 182 | border: 1px solid #e5e0c6; 183 | border-radius: 4px; 184 | } 185 | .curl_title { 186 | font-size: 1.1em; 187 | margin: 0; 188 | padding: 15px 0 5px; 189 | font-family: 'Open Sans', 'Helvetica Neue', Arial, sans-serif; 190 | font-weight: 500; 191 | line-height: 1.1; 192 | } 193 | .footer { 194 | display: none; 195 | } 196 | .swagger-section .swagger-ui-wrap h2 { 197 | padding: 0; 198 | } 199 | h2 { 200 | margin: 0; 201 | margin-bottom: 5px; 202 | } 203 | .markdown p { 204 | font-size: 15px; 205 | font-family: 'Arvo', serif; 206 | } 207 | .swagger-section .swagger-ui-wrap .code { 208 | font-size: 15px; 209 | font-family: 'Arvo', serif; 210 | } 211 | .swagger-section .swagger-ui-wrap b { 212 | font-family: 'Arvo', serif; 213 | } 214 | #signin:hover { 215 | cursor: pointer; 216 | } 217 | .dropdown-menu { 218 | padding: 15px; 219 | } 220 | .navbar-right .dropdown-menu { 221 | left: 0; 222 | right: auto; 223 | } 224 | #signinbutton { 225 | width: 100%; 226 | height: 32px; 227 | font-size: 13px; 228 | font-weight: bold; 229 | color: #08b; 230 | } 231 | .navbar-default .nav > li .details { 232 | color: #000000; 233 | text-transform: none; 234 | font-size: 15px; 235 | font-weight: normal; 236 | font-family: 'Open Sans', sans-serif; 237 | font-style: italic; 238 | line-height: 20px; 239 | top: -2px; 240 | } 241 | .navbar-default .nav > li .details:hover { 242 | color: black; 243 | } 244 | #signout { 245 | width: 100%; 246 | height: 32px; 247 | font-size: 13px; 248 | font-weight: bold; 249 | color: #08b; 250 | } 251 | -------------------------------------------------------------------------------- /src/main/resources/public/css/typography.css: -------------------------------------------------------------------------------- 1 | /* droid-sans-regular - latin */ 2 | @font-face { 3 | font-family: 'Droid Sans'; 4 | font-style: normal; 5 | font-weight: 400; 6 | src: url('../fonts/droid-sans-v6-latin-regular.eot'); /* IE9 Compat Modes */ 7 | src: local('Droid Sans'), local('DroidSans'), 8 | url('../fonts/droid-sans-v6-latin-regular.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 9 | url('../fonts/droid-sans-v6-latin-regular.woff2') format('woff2'), /* Super Modern Browsers */ 10 | url('../fonts/droid-sans-v6-latin-regular.woff') format('woff'), /* Modern Browsers */ 11 | url('../fonts/droid-sans-v6-latin-regular.ttf') format('truetype'), /* Safari, Android, iOS */ 12 | url('../fonts/droid-sans-v6-latin-regular.svg#DroidSans') format('svg'); /* Legacy iOS */ 13 | } 14 | /* droid-sans-700 - latin */ 15 | @font-face { 16 | font-family: 'Droid Sans'; 17 | font-style: normal; 18 | font-weight: 700; 19 | src: url('../fonts/droid-sans-v6-latin-700.eot'); /* IE9 Compat Modes */ 20 | src: local('Droid Sans Bold'), local('DroidSans-Bold'), 21 | url('../fonts/droid-sans-v6-latin-700.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */ 22 | url('../fonts/droid-sans-v6-latin-700.woff2') format('woff2'), /* Super Modern Browsers */ 23 | url('../fonts/droid-sans-v6-latin-700.woff') format('woff'), /* Modern Browsers */ 24 | url('../fonts/droid-sans-v6-latin-700.ttf') format('truetype'), /* Safari, Android, iOS */ 25 | url('../fonts/droid-sans-v6-latin-700.svg#DroidSans') format('svg'); /* Legacy iOS */ 26 | } 27 | -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-700.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-700.eot -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-700.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-700.ttf -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-700.woff -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-700.woff2 -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-regular.eot -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-regular.ttf -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-regular.woff -------------------------------------------------------------------------------- /src/main/resources/public/fonts/droid-sans-v6-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/fonts/droid-sans-v6-latin-regular.woff2 -------------------------------------------------------------------------------- /src/main/resources/public/images/explorer_icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/explorer_icons.png -------------------------------------------------------------------------------- /src/main/resources/public/images/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/favicon-16x16.png -------------------------------------------------------------------------------- /src/main/resources/public/images/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/favicon-32x32.png -------------------------------------------------------------------------------- /src/main/resources/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/favicon.ico -------------------------------------------------------------------------------- /src/main/resources/public/images/logo_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/logo_small.png -------------------------------------------------------------------------------- /src/main/resources/public/images/pet_store_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/pet_store_api.png -------------------------------------------------------------------------------- /src/main/resources/public/images/throbber.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/throbber.gif -------------------------------------------------------------------------------- /src/main/resources/public/images/wordnik_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkMobile/spring-restful-authorization/b686c34519d6056feb161114f195a01b32119b74/src/main/resources/public/images/wordnik_api.png -------------------------------------------------------------------------------- /src/main/resources/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | spring-token 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 87 | 88 | 89 | 90 | 100 | 101 |
 
102 |
103 | 104 | 105 | -------------------------------------------------------------------------------- /src/main/resources/public/lib/backbone-min.js: -------------------------------------------------------------------------------- 1 | // Backbone.js 1.1.2 2 | 3 | (function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('