STS創建Spring Boot項目實戰(Rest接口、數據庫、用戶認證、分佈式Token JWT、Redis操作、日誌和統一異常處理)

1.項目創建


1、新建工程




2、選擇打包方式,這邊可以選擇爲打包爲Jar包,或者傳統的打包爲War包



3、選擇開發過程中使用到的技術,這邊我選擇的是Rest Repositories



4、新建測試用Controller



    文件內容如下

[java] view plain copy
  1. package com.xiaofangtech.example;  
  2.   
  3. import org.springframework.web.bind.annotation.RequestMapping;  
  4. import org.springframework.web.bind.annotation.RestController;  
  5.   
  6. @RestController  
  7. public class HelloController {  
  8.     @RequestMapping("/greeting")  
  9.     public String hello()  
  10.     {  
  11.         return "Hello world";  
  12.     }  
  13. }  

5、以Srping Boot App 方式運行



正常運行後控制檯如下



6、測試運行


至此,一個最簡單的hello world的工程創建運行完成


7、打包部署

   7.1 打包爲可運行jar包

   使用mvn package 進行打包

   



 然後run ,運行成功後如下生成jar包






 7.2 打包爲傳統的war包 

       當第2步中選擇的打包方式爲war時,執行7.1中mvn package時,生成的包就是war包

     



運行war包跟運行jar包一樣,找到war包所在目錄,註解運行war包


D:\new_tech\spring-suite-tool\workspace\workspace1\demo1\target>java -jar demo1-0.0.1-SNAPSHOT.war


訪問服務接口: localhost:8080/greeting



2.代碼實現連接數據實現Rest接口和Basic 基礎認證

0.引入pom依賴

  1. <dependency>
  2. <groupId>org.projectlombok</groupId>
  3. <artifactId>lombok</artifactId>
  4. </dependency>
  5. <!-- 使用MySQL數據庫,並用Spring Data JPA來作爲數據庫訪問 -->
  6. <dependency>
  7. <groupId>org.springframework.boot</groupId>
  8. <artifactId>spring-boot-starter-data-jpa</artifactId>
  9. </dependency>
  10. <dependency>
  11. <groupId>mysql</groupId>
  12. <artifactId>mysql-connector-java</artifactId>
  13. </dependency>




1.代碼整體結構



2.註冊Filter過濾器的兩種方式:
        1.在自定義的Filter上使用註解:
           
  1. /*
  2. * Filter實現簡單的Http Basic 認證
  3. */
  4. @Component
  5. @WebFilter(filterName = "httpBasicAuthorizedFilter", urlPatterns="/user/*")
  6. public class HttpBasicAuthorizeFilter implements Filter {

       2.在配置類中定義Filter

  1. @Bean
  2. public FilterRegistrationBean filterRegistrationBean() {
  3. FilterRegistrationBean registrationBean = new FilterRegistrationBean();
  4. HttpBasicAuthorizeFilter httpBasicFilter = new HttpBasicAuthorizeFilter();
  5. registrationBean.setFilter(httpBasicFilter);
  6. List<String> urlPatterns = new ArrayList<String>();
  7. urlPatterns.add("/user/*");
  8. registrationBean.setUrlPatterns(urlPatterns);
  9. return registrationBean;
  10. }


3.數據庫和Rest接口操作效果展示:



4.過濾器效果展示
  
代碼中固定用戶名密碼都爲test,所以對接口進行請求時,需要添加以下認證頭信息

Authorization: Basic dGVzdDp0ZXN0

dGVzdDp0ZXN0 爲 test:test 經過base64編碼後的結果


如果未添加認證信息或者認證信息錯誤,返回沒有權限的錯誤信息




當認證信息正確,返回請求結果



3.自定義Properties解析類和分佈式Token JWT用戶校驗

    1.自定義Properties解析類的使用規則

                  1.定義Properties配置文件   ---- jwt.properties
                      
  1. jwt.info.clientId=098f6bcd4621d373cade4e832627b4f6
  2. jwt.info.base64Secret=MDk4ZjZiY2Q0NjIxZDM3M2NhZGU0ZTgzMjYyN2I0ZjY=
  3. jwt.info.name=restapiuser
  4. jwt.info.expiresSecond=172800


                  2.自定義解析類                      ---- JwtInfo.java  指定配置文件地址和配置前綴,屬性是前綴之後的名稱
  1. package com.jay.properties;
  2. import org.springframework.boot.context.properties.ConfigurationProperties;
  3. /*
  4. * 自定義配置文件的解析類
  5. */
  6. @ConfigurationProperties(prefix = "jwt.info", locations = "classpath:/config/jwt.properties")
  7. public class JwtInfo {
  8. private String clientId;
  9. private String base64Secret;
  10. private String name;
  11. private int expiresSecond;
  12. public String getClientId() {
  13. return clientId;
  14. }
  15. public void setClientId(String clientId) {
  16. this.clientId = clientId;
  17. }
  18. public String getBase64Secret() {
  19. return base64Secret;
  20. }
  21. public void setBase64Secret(String base64Secret) {
  22. this.base64Secret = base64Secret;
  23. }
  24. public String getName() {
  25. return name;
  26. }
  27. public void setName(String name) {
  28. this.name = name;
  29. }
  30. public int getExpiresSecond() {
  31. return expiresSecond;
  32. }
  33. public void setExpiresSecond(int expiresSecond) {
  34. this.expiresSecond = expiresSecond;
  35. }
  36. }



                  3.啓動類或配置類中,指定自定義Properties解析類
  1. package com.jay;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties.Jwt;
  5. import org.springframework.boot.context.properties.EnableConfigurationProperties;
  6. import org.springframework.boot.web.servlet.ServletComponentScan;
  7. import com.jay.properties.JwtInfo;
  8. @SpringBootApplication
  9. @EnableConfigurationProperties(JwtInfo.class) //加載自定義的properties解析類
  10. public class Demo1Application {
  11. public static void main(String[] args) {
  12. SpringApplication.run(Demo1Application.class, args);
  13. }
  14. }

               4.輸出配置文件信息         ---- JwtInfoController.java

  1. package com.jay.controller;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RequestMethod;
  5. import org.springframework.web.bind.annotation.RestController;
  6. import com.jay.properties.JwtInfo;
  7. import com.jay.vo.ResultMsg;
  8. import com.jay.vo.ResultStatusCode;
  9. @RestController
  10. @RequestMapping("/jwt")
  11. public class JwtInfoController {
  12. @Autowired
  13. private JwtInfo jwtInfo;
  14. @RequestMapping(value = "/info", method = RequestMethod.GET)
  15. public Object getJwtInfo() {
  16. return new ResultMsg<JwtInfo>(true, ResultStatusCode.OK.getErrorCode(), ResultStatusCode.OK.getErrorMsg(), jwtInfo);
  17. }
  18. }

               5.效果展示
              


          2.使用分佈式token  JWT進行用戶認證


              

jwt(json web token)

用戶發送按照約定,向服務端發送 Header、Payload 和 Signature,幷包含認證信息(密碼),驗證通過後服務端返回一個token,之後用戶使用該token作爲登錄憑證,適合於移動端和api


jwt使用流程



              1.添加 JWT依賴
  1. <!-- JWT Json Web Token 依賴 -->
  2. <dependency>
  3. <groupId>io.jsonwebtoken</groupId>
  4. <artifactId>jjwt</artifactId>
  5. <version>0.7.0</version>
  6. </dependency>

             2.編寫Jwt解析類和Jwt過濾器
             
  1. package com.jay.util.jwt;
  2. import java.security.Key;
  3. import java.util.Date;
  4. import javax.crypto.spec.SecretKeySpec;
  5. import javax.xml.bind.DatatypeConverter;
  6. import io.jsonwebtoken.Claims;
  7. import io.jsonwebtoken.JwtBuilder;
  8. import io.jsonwebtoken.Jwts;
  9. import io.jsonwebtoken.SignatureAlgorithm;
  10. /*
  11. * 構造及解析jwt的工具類
  12. */
  13. public class JwtHelper {
  14. public static Claims parseJWT(String jsonWebToken, String base64Security){
  15. try
  16. {
  17. Claims claims = Jwts.parser()
  18. .setSigningKey(DatatypeConverter.parseBase64Binary(base64Security))
  19. .parseClaimsJws(jsonWebToken).getBody();
  20. return claims;
  21. }
  22. catch(Exception ex)
  23. {
  24. return null;
  25. }
  26. }
  27. /**
  28. * 生成token
  29. *
  30. * @author hetiewei
  31. * @date 2016年10月18日 下午2:51:38
  32. * @param name keyId
  33. * @param userId
  34. * @param role
  35. * @param audience 接收者
  36. * @param issuer 發行者
  37. * @param TTLMillis 過期時間(毫秒)
  38. * @param base64Security
  39. * @return
  40. */
  41. public static String createJWT(String name, String userId, String role,
  42. String audience, String issuer, long TTLMillis, String base64Security)
  43. {
  44. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  45. long nowMillis = System.currentTimeMillis();
  46. Date now = new Date(nowMillis);
  47. //生成簽名密鑰
  48. byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
  49. Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
  50. //添加構成JWT的參數
  51. JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
  52. .claim("role", role)
  53. .claim("unique_name", name)
  54. .claim("userid", userId)
  55. .setIssuer(issuer)
  56. .setAudience(audience)
  57. .signWith(signatureAlgorithm, signingKey);
  58. //添加Token過期時間
  59. if (TTLMillis >= 0) {
  60. long expMillis = nowMillis + TTLMillis;
  61. Date exp = new Date(expMillis);
  62. builder.setExpiration(exp).setNotBefore(now);
  63. }
  64. //生成JWT
  65. return builder.compact();
  66. }
  67. }




  1. package com.jay.filter;
  2. import java.io.IOException;
  3. import javax.servlet.Filter;
  4. import javax.servlet.FilterChain;
  5. import javax.servlet.FilterConfig;
  6. import javax.servlet.ServletException;
  7. import javax.servlet.ServletRequest;
  8. import javax.servlet.ServletResponse;
  9. import javax.servlet.http.HttpServletRequest;
  10. import javax.servlet.http.HttpServletResponse;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.web.context.support.SpringBeanAutowiringSupport;
  13. import com.fasterxml.jackson.databind.ObjectMapper;
  14. import com.jay.properties.JwtInfo;
  15. import com.jay.util.jwt.JwtHelper;
  16. import com.jay.vo.ResultMsg;
  17. import com.jay.vo.ResultStatusCode;
  18. /*
  19. * 用於JWT認證的過濾器
  20. */
  21. public class JwtAuthorizeFilter implements Filter{
  22. /*
  23. * 注入配置文件類
  24. */
  25. @Autowired
  26. private JwtInfo jwtInfo;
  27. @Override
  28. public void destroy() {
  29. }
  30. @Override
  31. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
  32. throws IOException, ServletException {
  33. ResultMsg<Object> resultMsg;
  34. HttpServletRequest httpRequest = (HttpServletRequest)request;
  35. String auth = httpRequest.getHeader("Authorization");
  36. if ((auth != null) && (auth.length() > 7))
  37. {
  38. String HeadStr = auth.substring(0, 6).toLowerCase();
  39. if (HeadStr.compareTo("bearer") == 0)
  40. {
  41. auth = auth.substring(7, auth.length());
  42. if (JwtHelper.parseJWT(auth, jwtInfo.getBase64Secret()) != null)
  43. {
  44. chain.doFilter(request, response);
  45. return;
  46. }
  47. }
  48. }
  49. //驗證不通過
  50. HttpServletResponse httpResponse = (HttpServletResponse) response;
  51. httpResponse.setCharacterEncoding("UTF-8");
  52. httpResponse.setContentType("application/json; charset=utf-8");
  53. httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
  54. //將驗證不通過的錯誤返回
  55. ObjectMapper mapper = new ObjectMapper();
  56. resultMsg = new ResultMsg<Object>(true, ResultStatusCode.INVALID_TOKEN.getErrorCode(), ResultStatusCode.INVALID_TOKEN.getErrorMsg(), null);
  57. httpResponse.getWriter().write(mapper.writeValueAsString(resultMsg));
  58. return;
  59. }
  60. @Override
  61. public void init(FilterConfig filterConfig) throws ServletException {
  62. SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, filterConfig.getServletContext());
  63. }
  64. }







            3.在Jwt配置類中,添加過濾器
             
  1. package com.jay.config;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. import org.springframework.boot.context.embedded.FilterRegistrationBean;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. import com.jay.filter.JwtAuthorizeFilter;
  8. /*
  9. * 註冊jwt認證過濾器
  10. */
  11. @Configuration
  12. public class JwtConfig {
  13. /*
  14. * 註冊過濾器類和過濾的url
  15. */
  16. @Bean
  17. public FilterRegistrationBean basicFilterRegistrationBean(){
  18. FilterRegistrationBean registrationBean = new FilterRegistrationBean();
  19. JwtAuthorizeFilter filter = new JwtAuthorizeFilter();
  20. registrationBean.setFilter(filter);
  21. List<String> urlPatterns = new ArrayList<>();
  22. urlPatterns.add("/user/*");
  23. registrationBean.setUrlPatterns(urlPatterns);
  24. return registrationBean;
  25. }
  26. }

 
            
            4.效果展示:
                       1. 獲取token,傳入用戶認證信息





                    2.使用上面獲取的token進行接口調用,     未使用token,獲取token錯誤,或者token過期時



               3.使用正確的token時
                   

                    



特別注意:
              JWT使用時,可以通過Cookie機制,自動的傳遞!!!


4.Redis + Cookie 機制,進行驗證碼的校驗


1.添加redis和captcha庫依賴

  1. <!-- 整合redis -->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-redis</artifactId>
  5. </dependency>
  6. <!-- 第三方驗證碼庫 -->
  7. <dependency>
  8. <groupId>cn.apiclub.tool</groupId>
  9. <artifactId>simplecaptcha</artifactId>
  10. <version>1.2.2</version>
  11. </dependency>


2.redis配置

  1. ##Redis配置
  2. spring.redis.database=1
  3. spring.redis.host=localhost
  4. #spring.redis.password=password
  5. spring.redis.port=6379
  6. spring.redis.timeout=2000
  7. spring.redis.pool.max-idle=8
  8. spring.redis.pool.min-idle=0
  9. spring.redis.pool.max-active=8
  10. spring.redis.pool.max-wait=-1


3.Redis配置類,實例化Redis模板

  1. package com.jay.config;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.data.redis.connection.RedisConnectionFactory;
  5. import org.springframework.data.redis.core.RedisTemplate;
  6. import org.springframework.data.redis.core.StringRedisTemplate;
  7. import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
  8. import com.fasterxml.jackson.annotation.JsonAutoDetect;
  9. import com.fasterxml.jackson.annotation.PropertyAccessor;
  10. import com.fasterxml.jackson.databind.ObjectMapper;
  11. @Configuration
  12. public class RedisConfig {
  13. // 定義Redis模板
  14. @Bean
  15. public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
  16. StringRedisTemplate template = new StringRedisTemplate(factory);
  17. // 設置序列化工具, 這樣緩存的Bean就不需要再試下Serializable接口
  18. setSerrializer(template);
  19. template.afterPropertiesSet();
  20. return template;
  21. }
  22. // 設置序列化
  23. private void setSerrializer(StringRedisTemplate template) {
  24. Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
  25. ObjectMapper om = new ObjectMapper();
  26. om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
  27. om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
  28. jackson2JsonRedisSerializer.setObjectMapper(om);
  29. template.setValueSerializer(jackson2JsonRedisSerializer);
  30. }
  31. }


4.Controller層操作代碼

  1. package com.jay.controller;
  2. import java.io.ByteArrayOutputStream;
  3. import java.io.IOException;
  4. import java.util.UUID;
  5. import java.util.concurrent.TimeUnit;
  6. import javax.imageio.ImageIO;
  7. import javax.servlet.http.Cookie;
  8. import javax.servlet.http.HttpServletRequest;
  9. import javax.servlet.http.HttpServletResponse;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.http.HttpRequest;
  13. import org.springframework.http.MediaType;
  14. import org.springframework.stereotype.Controller;
  15. import org.springframework.web.bind.annotation.PathVariable;
  16. import org.springframework.web.bind.annotation.RequestMapping;
  17. import org.springframework.web.bind.annotation.RequestMethod;
  18. import org.springframework.web.bind.annotation.ResponseBody;
  19. import com.jay.util.CookieUtils;
  20. import com.jay.vo.ResultMsg;
  21. import com.jay.vo.ResultStatusCode;
  22. import cn.apiclub.captcha.Captcha;
  23. import cn.apiclub.captcha.backgrounds.GradiatedBackgroundProducer;
  24. import cn.apiclub.captcha.gimpy.FishEyeGimpyRenderer;
  25. import io.swagger.annotations.ApiOperation;
  26. @Controller
  27. @RequestMapping("/redis")
  28. public class RedisCaptchaController {
  29. @Autowired
  30. private RedisTemplate<String, String> redisTemplate;
  31. private static int captchaExpires = 3 * 60; // 超時時間3min,驗證碼超時,自動衝redis中刪除
  32. private static int captchaW = 200;
  33. private static int captchaH = 60;
  34. private static String cookieName = "CaptchaCode";
  35. @RequestMapping(value = "getcaptcha", method = RequestMethod.GET, produces = MediaType.IMAGE_PNG_VALUE)
  36. public @ResponseBody byte[] getCaptcha(HttpServletResponse response) {
  37. // 生成驗證碼
  38. String uuid = UUID.randomUUID().toString();
  39. Captcha captcha = new Captcha.Builder(captchaW, captchaH).addText()
  40. .addBackground(new GradiatedBackgroundProducer()).gimp(new FishEyeGimpyRenderer()).build();
  41. // 將驗證碼以<key,value>形式緩存到redis
  42. redisTemplate.opsForValue().set(uuid, captcha.getAnswer(), captchaExpires, TimeUnit.SECONDS);
  43. // 將驗證碼key,及驗證碼的圖片返回
  44. Cookie cookie = new Cookie(cookieName, uuid);
  45. response.addCookie(cookie);
  46. ByteArrayOutputStream bao = new ByteArrayOutputStream();
  47. try {
  48. ImageIO.write(captcha.getImage(), "png", bao);
  49. return bao.toByteArray();
  50. } catch (IOException e) {
  51. return null;
  52. }
  53. }
  54. /*
  55. * 說明:
  56. * 1.captchaCode來自客戶端的Cookie,在訪問時,通過服務端設置
  57. * 2.captcha是用戶填寫的驗證碼,將用戶填寫的驗證碼和通過captchaCode從redis中獲取的驗證碼進行對比即可
  58. *
  59. */
  60. @ApiOperation(value = "驗證碼校驗")
  61. @RequestMapping(value = "/captcha/check/{captcha}")
  62. @ResponseBody
  63. public ResultMsg<Object> checkCaptcha(@PathVariable("captcha") String captcha, HttpServletRequest request){
  64. String captchaCode = CookieUtils.getCookie(request, cookieName);
  65. ResultMsg<Object> result;
  66. try{
  67. if (captcha == null)
  68. {
  69. throw new Exception();
  70. }
  71. //redis中查詢驗證碼
  72. String captchaValue = redisTemplate.opsForValue().get(captchaCode);
  73. if (captchaValue == null) {
  74. throw new Exception();
  75. }
  76. if (captchaValue.compareToIgnoreCase(captcha) != 0) {
  77. throw new Exception();
  78. }
  79. //驗證碼匹配成功,redis則刪除對應的驗證碼
  80. redisTemplate.delete(captchaCode);
  81. return new ResultMsg<Object>(true, ResultStatusCode.OK.getErrorCode(), ResultStatusCode.OK.getErrorMsg(), null);
  82. }catch (Exception e) {
  83. result = new ResultMsg<Object>(false, ResultStatusCode.INVALID_CAPTCHA.getErrorCode(), ResultStatusCode.INVALID_CAPTCHA.getErrorMsg(), null);
  84. }
  85. return result;
  86. }
  87. }


5.效果展示

1.訪問生成驗證碼



2.驗證驗證碼



項目源碼下載:下載地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章