前言 在之前的學習 "springBoot" 中,成功的實現了Restful風格的基本服務。但是想將之前的工程作為一個項目來說,那些是僅僅不夠的。可能還需要獲取自定義的配置以及添加過濾器和攔截器。至於為什麼將這些寫在一起,只是因為這些比較簡單而且也會經常用到,所以乾脆就一起寫出來了。 讀取配置文件 ...
前言
在之前的學習springBoot中,成功的實現了Restful風格的基本服務。但是想將之前的工程作為一個項目來說,那些是僅僅不夠的。可能還需要獲取自定義的配置以及添加過濾器和攔截器。至於為什麼將這些寫在一起,只是因為這些比較簡單而且也會經常用到,所以乾脆就一起寫出來了。
讀取配置文件
在使用maven項目中,配置文件會放在resources根目錄下。
我們的springBoot是用Maven搭建的,所以springBoot的預設配置文件和自定義的配置文件都放在此目錄。
springBoot的 預設配置文件為 application.properties 或 application.yml,這裡我們使用 application.properties。
首先在application.properties中添加我們要讀取的數據。
springBoot支持分層結構。
例如:
web:
pancm:
title: SpringBoot
description: test
註意前面的空格!
在application.properties添加完之後,我們便在代碼中進行讀取。
這裡我們使用**@Value** 方式。
首先在類中添加 **@Component**、**@ConfigurationProperties**這兩個註解。
第一個註解表示這個類是獲取配置文件,第二個註解表示從配置文件中獲取的數據轉換為對象。因為我們使用了層級結構,獲取web.pancm目錄下的參數,所以我們再加上prefix = "web.pancm"這個表示獲取這之後的數據,就避免了下麵在重覆書寫。
那麼代碼如下:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
*
* Title: MyProperties
* Description:
* 從application.properties 獲取 配置
* Version:1.0.0
* @author pancm
* @date 2018年1月11日
*/
@Component
@ConfigurationProperties(prefix = "web.pancm")
public class MyProperties {
/**
* 獲取個人標題
*
*/
@Value("${title}")
private String title;
/**
* 獲取個人描述
*/
@Value("${description}")
private String description;
/** get和set略 */
}
本類中可以直接獲取該屬性,不過在外部類調用的時候,需要添加**@Autowired**。
例如:
@Autowired
MyProperties myProperties;
System.out.println(myProperties.getTitle());
System.out.println(myProperties.getDescription());
上面的是獲取application.properties中的方法。
如果想自定義配置文件和屬性的話,只需再添加一個**@PropertySource**註解就可,然後添加 value屬性,指向文件路徑即可。
例如:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
/**
*
* Title: MyConfig
* Description:
* 自定義配置文件
* Version:1.0.0
* @author pancm
* @date 2018年1月20日
*/
@Component
@ConfigurationProperties(prefix = "myconfig")
@PropertySource(value = "classpath:myconfig.proferties")
public class MyConfig {
@Value("${test}")
private String test;
public String getTest() {
return test;
}
public void setTest(String test) {
this.test = test;
}
}
調用方法同上!
註: 之前的springBoot版本的@ConfigurationProperties註解可以使用 locations 方法來指定自定義配置文件路徑,不過在 springBoot 1.5以上的就已經不支持 location屬性,所以這裡使用的是PropertySource。
過濾器
過濾器是什麼?
簡單的來說,過濾器就是過濾的作用,在web開發中過濾一些我們指定的url。
過濾器主要做什麼?
過濾掉一些不需要的東西,例如一些錯誤的請求。
也可以修改請求和相應的內容。
過濾器的代碼實現
過濾器(filter)有三個方法,其中初始化(init)和摧毀(destroy)方法一般不會用到,主要用到的是doFilter這個方法。
而至於怎麼過濾呢?
如果過濾通過,則在doFilter執行filterChain.doFilter(request,response);
該方法。
這裡我們在過濾器中設置下請求的時間, 符合就通過。否則返回錯誤信息!
代碼示例:
class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest srequest, ServletResponse sresponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) srequest;
//執行過濾操作...
System.out.println("請求的url :"+request.getRequestURI());
// 獲取系統時間
Calendar ca = Calendar.getInstance();
int hour = ca.get(Calendar.HOUR_OF_DAY);
// 設置限制運行時間
if (0<hour && hour < 18) {
HttpServletResponse response = (HttpServletResponse) sresponse;
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
// 消息
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("status", "1");
messageMap.put("message", "此介面可以請求時間為:18-24點");
ObjectMapper objectMapper=new ObjectMapper();
String writeValueAsString = objectMapper.writeValueAsString(messageMap);
response.getWriter().write(writeValueAsString);
return;
}
filterChain.doFilter(srequest, sresponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("參數初始化:"+filterConfig);
}
@Override
public void destroy() {
System.out.println("開始銷毀...");
}
}
那麼在springBoot中如何使用過濾器呢?
一般是使用Component和WebFilter 這兩個註解,但是這裡我們就直接方法調用。
在該方法中添加Bean註解,springBoot會在啟動的時候進行調用。並指定需要過濾的請求。
代碼示例:
@Bean
public FilterRegistrationBean testFilterRegistration() {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(new MyFilter());
//過濾掉 /getUser 和/hello 的請求
registration.addUrlPatterns("/getUser","/hello");
//過濾掉所有請求
// registration.addUrlPatterns("/*");
registration.setName("MyFilter");
registration.setOrder(1);
return registration;
}
說明: registration.setOrder() 方法是設置優先順序,數值越大,優先順序越高。
攔截器
攔截器是什麼?
簡單的來說,就是一道閥門,攔截不需要的東西。
攔截器主要做什麼?
對正在運行的流程進行干預。
攔截器的代碼實現。
攔截器也主要有三個方法,其中preHandle是在請求之前就進行調用,如果該請求需要被攔截,則返回false,否則true; postHandle是在請求之後進行調用,無返回值;afterCompletion是在請求結束的時候進行調用,無返回值。
這裡我們就簡單的模擬下攔截非白名單的IP請求。
代碼示例:
class MyInterceptor implements HandlerInterceptor {
@Autowired
private IpConfig ipconfig;
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
String ip = getIpAddr(request);
// 獲取可以訪問系統的白名單
String ipStr = ipconfig.getIpWhiteList();
String[] ipArr = ipStr.split("\\|");
List<String> ipList = Arrays.asList(ipArr);
if (ipList.contains(ip)) {
System.out.println("該IP: " + ip+"通過!");
return true;
} else {
System.out.println("該IP: " + ip+"不通過!");
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json; charset=utf-8");
// 消息
Map<String, Object> messageMap = new HashMap<>();
messageMap.put("status", "1");
messageMap.put("message", "您好,ip為" + ip + ",暫時沒有訪問許可權,請聯繫管理員開通訪問許可權。");
ObjectMapper objectMapper=new ObjectMapper();
String writeValueAsString = objectMapper.writeValueAsString(messageMap);
response.getWriter().write(writeValueAsString);
return false;
}
}
public String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("X-Forwarded-For");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle被調用");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("afterCompletion被調用");
}
}
依舊再啟動springBoot的時候啟動攔截器,並指定攔截的請求。
代碼示例:
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pancm.springboot_config.config.IpConfig;
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
@Bean
public HandlerInterceptor getMyInterceptor(){
return new MyInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns 用於添加攔截規則, 這裡假設攔截 /url 後面的全部鏈接
// excludePathPatterns 用戶排除攔截
registry.addInterceptor(getMyInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
}
結語
關於springBoot配置文件的獲取以及過濾器和攔截器的使用暫時就介紹到這了。如果在某些方面描述的不夠清楚或者說的不太正確,希望讀者能指出。
該項目完整的代碼我放到github上了,有興趣的可以看看。
https://github.com/xuwujing/springBoot