SpringBoot中使用 攔截器
阿新 • • 發佈:2019-01-07
在web開發的過程中,為了實現登入許可權驗證,我們往往需要新增一個攔截器在使用者的的請求到達controller層的時候實現登入驗證,那麼SpringBoot如何新增攔截器呢?
步驟如下:
1.繼承WebMvcConfigureAdapter類,覆蓋其addInterceptors介面,註冊我們自定義的攔截器:
/** * * 註冊攔截器 * Created by SYSTEM on 2017/8/16. */ public class WebAppConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors(InterceptorRegistry registry) { //註冊自定義攔截器,新增攔截路徑和排除攔截路徑 registry.addInterceptor(new InterceptorConfig()).addPathPatterns("api/path/**").excludePathPatterns("api/path/login"); } }
2.實現HandlerInterceptor介面,重寫介面中的三個方法:
public class InterceptorConfig implements HandlerInterceptor{ private static final Logger log = LoggerFactory.getLogger(InterceptorConfig.class); /** * 進入controller層之前攔截請求 * @param httpServletRequest * @param httpServletResponse * @param o * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { log.info("---------------------開始進入請求地址攔截--- 從session獲取資料如果存在就放行不存在就丟擲異常攔截-------------------------"); HttpSession session = httpServletRequest.getSession(); if(!StringUtils.isEmpty(session.getAttribute("userName"))){ return true; } else{ PrintWriter printWriter = httpServletResponse.getWriter(); printWriter.write("{code:0,message:\"session is invalid,please login again!\"}"); return false; } } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { log.info("--------------處理請求完成後檢視渲染之前的處理操作---------------"); } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { log.info("---------------檢視渲染之後的操作-------------------------0"); } }
註冊攔截器
@Configuration
public class MyWebConfig extends WebMvcConfigurerAdapter{
/**
* 註冊 攔截器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LogHandlerInterceptor());
}
}
測試:這樣我們就可以在使用者請求到達controller層實現登入攔截了,所有使用者請求都會被攔截,在prehandle方法進行登入判斷,返回true則驗證通過,否則失敗UserController
@RestController
public class UserController {
@GetMapping("/user/home")
public String home(){
System.out.println("--- user home ---");
return "user home";
}
}
redis==========================
1、引入 spring-boot-starter-redis(1.4版本前),spring-boot-starter-data-redis(1.4版本後)
<!-- cache --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <!-- redis --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
2,application.properties 配置檔案
# Redis資料庫索引(預設為0)
spring.redis.database=0
# Redis伺服器地址
spring.redis.host=localhost
# Redis伺服器連線埠
spring.redis.port=6379
# Redis伺服器連線密碼(預設為空)
spring.redis.password=
# 連線池最大連線數(使用負值表示沒有限制)
spring.redis.pool.max-active=8
# 連線池最大阻塞等待時間(使用負值表示沒有限制)
spring.redis.pool.max-wait=-1
# 連線池中的最大空閒連線
spring.redis.pool.max-idle=8
# 連線池中的最小空閒連線
spring.redis.pool.min-idle=0
# 連線超時時間(毫秒)
spring.redis.timeout=0
2.SpringBoot配置檔案中配置Redis連線(YAML方式配置)
spring:
application:
name: spring-boot-redis
redis:
host: 192.168.145.132
port: 6379
timeout: 20000
cluster:
nodes: 192.168.211.134:7000,192.168.211.134:7001,192.168.211.134:7002
maxRedirects: 6
pool:
max-active: 8
min-idle: 0
max-idle: 8
max-wait: -1
解釋:本配置採用Redis一主三從的的配置方式來提高快取的吞吐量
3.Redis快取配置類提供redisTemplate(獲得配置檔案中連線引數後的)
@Configuration
@EnableCaching
public class RedisCacheConfig {
@Bean
public CacheManager cacheManager(RedisTemplate<?, ?> redisTemplate){
CacheManager cacheManager = new RedisCacheManager(redisTemplate);
return cacheManager;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, String> redisTemplate = new RedisTemplate<String,String>();
redisTemplate.setConnectionFactory(factory);
// key序列化方式;(不然會出現亂碼;),但是如果方法上有Long等非String型別的話,會報型別轉換錯誤;
// 所以在沒有自己定義key生成策略的時候,以下這個程式碼建議不要這麼寫,可以不配置或者自己實現ObjectRedisSerializer
// 或者JdkSerializationRedisSerializer序列化方式;
RedisSerializer<String> redisSerializer = new StringRedisSerializer();// Long型別不可以會出現異常資訊;
redisTemplate.setKeySerializer(redisSerializer);
redisTemplate.setHashKeySerializer(redisSerializer);
return redisTemplate;
}
}
Redis工具類
/**
* redicache 工具類
*
*/
@SuppressWarnings("unchecked")
@Component
public class RedisUtil {
@SuppressWarnings("rawtypes")
@Autowired
private RedisTemplate redisTemplate;
/**
* 寫入快取
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 寫入快取設定時效時間
* @param key
* @param value
* @return
*/
public boolean set(final String key, Object value, Long expireTime) {
boolean result = false;
try {
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
operations.set(key, value);
redisTemplate.expire(key, expireTime, TimeUnit.SECONDS);
result = true;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
/**
* 批量刪除對應的value
* @param keys
*/
public void remove(final String... keys) {
for (String key : keys) {
remove(key);
}
}
/**
* 批量刪除key
* @param pattern
*/
public void removePattern(final String pattern) {
Set<Serializable> keys = redisTemplate.keys(pattern);
if (keys.size() > 0)
redisTemplate.delete(keys);
}
/**
* 刪除對應的value
* @param key
*/
public void remove(final String key) {
if (exists(key)) {
redisTemplate.delete(key);
}
}
/**
* 判斷快取中是否有對應的value
* @param key
* @return
*/
public boolean exists(final String key) {
return redisTemplate.hasKey(key);
}
/**
* 讀取快取
* @param key
* @return
*/
public Object get(final String key) {
Object result = null;
ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
result = operations.get(key);
return result;
}
/**
* 雜湊 新增
* @param key
* @param hashKey
* @param value
*/
public void hmSet(String key, Object hashKey, Object value){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
hash.put(key,hashKey,value);
}
/**
* 雜湊獲取資料
* @param key
* @param hashKey
* @return
*/
public Object hmGet(String key, Object hashKey){
HashOperations<String, Object, Object> hash = redisTemplate.opsForHash();
return hash.get(key,hashKey);
}
/**
* 列表新增
* @param k
* @param v
*/
public void lPush(String k,Object v){
ListOperations<String, Object> list = redisTemplate.opsForList();
list.rightPush(k,v);
}
/**
* 列表獲取
* @param k
* @param l
* @param l1
* @return
*/
public List<Object> lRange(String k, long l, long l1){
ListOperations<String, Object> list = redisTemplate.opsForList();
return list.range(k,l,l1);
}
/**
* 集合新增
* @param key
* @param value
*/
public void add(String key,Object value){
SetOperations<String, Object> set = redisTemplate.opsForSet();
set.add(key,value);
}
/**
* 集合獲取
* @param key
* @return
*/
public Set<Object> setMembers(String key){
SetOperations<String, Object> set = redisTemplate.opsForSet();
return set.members(key);
}
/**
* 有序集合新增
* @param key
* @param value
* @param scoure
*/
public void zAdd(String key,Object value,double scoure){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
zset.add(key,value,scoure);
}
/**
* 有序集合獲取
* @param key
* @param scoure
* @param scoure1
* @return
*/
public Set<Object> rangeByScore(String key,double scoure,double scoure1){
ZSetOperations<String, Object> zset = redisTemplate.opsForZSet();
return zset.rangeByScore(key, scoure, scoure1);
}
}
5.使用方法 測試用的Controller
import com.example.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@RequestMapping(value = "/test",method = RequestMethod.POST)
public void demoTest(){
RedisUtil.set("1","value22222");
}}將使用者資訊儲存到redis中
1.繼承WebMvcConfigureAdapter類,覆蓋其addInterceptors介面,註冊我們自定義的攔截器:
@Configuration
public class MyWebAppConfigurer extends WebMvcConfigurerAdapter {
@Bean
public HandlerInterceptor getMyInterceptor(){
return new MyHandlerInterceptor();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns 用於新增攔截規則, 這裡假設攔截 /url 後面的全部連結
// excludePathPatterns 使用者排除攔截
registry.addInterceptor(getMyInterceptor()).addPathPatterns("/api/*");
super.addInterceptors(registry);
}
}
2.實現HandlerInterceptor介面,重寫介面中的三個方法:
public class MyHandlerInterceptor implements HandlerInterceptor {
private final Logger logger = LoggerFactory.getLogger(MyHandlerInterceptor.class);
@Autowired
private RedConf conf;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
HttpServletResponse httpResponse = (HttpServletResponse) httpServletResponse;
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json; charset=utf-8");
PrintWriter out = null;
boolean retMsg = false;
String token = httpServletRequest.getHeader("token");
if (null == token || token.isEmpty()) {
//json 形式返回前端
JSONObject res = new JSONObject();
res.put("success", "false");
res.put("msg", "token沒有認證通過!原因為:客戶端請求引數中無token資訊");
out = httpResponse.getWriter();
out.append(res.toString());
logger.info("token沒有認證通過!原因為:客戶端請求引數中無token資訊");
return retMsg;
} else {
Jedis jedis = RedisUtil.getJedis(conf.getRedisIp(),Integer.parseInt(conf.getRedisPort()),1000,conf.getRedisAuth());
boolean exits = jedis.exists(token);
if (exits) {
jedis.expire(token, 900);
retMsg = true;
logger.info("認證成功");
RedisUtil.returnResource(jedis);
return retMsg;
} else {
JSONObject res = new JSONObject();
res.put("success", "false");
res.put("msg", "當前的token已過期,請重新登陸");
out = httpResponse.getWriter();
out.append(res.toString());
logger.info("當前的token已過期,請重新登陸");
return retMsg;
}
}
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}