在進(jìn)行 SpringBoot 項目開發(fā)的過程中,對于 SpringBoot 自帶的默認(rèn)配置我們難免有自己不喜歡的地方。或者你認(rèn)為更合理更想要的處理方式,這種時候你就可以選擇配置自己的處理邏輯。
如果Spring Boot提供的Sping MVC不符合要求,則可以通過一個配置類(注解有@Configuration的類)加上@EnableWebMvc注解來實現(xiàn)完全自己控制的MVC配置。
@EnableWebMvc
@Configuration
public class TestMvc {
···
}
通常情況下,Spring Boot的自動配置是符合我們大多數(shù)需求的。在你既需要保留Spring Boot提供的便利,有需要增加自己的額外的配置的時候,可以定義一個配置類并繼承WebMvcConfigurerAdapter,無需使用@EnableWebMvc注解。
@Configuration
public class TestMvc extends WebMvcConfigurerAdapter{
···
}
這里我們提到這個WebMvcConfigurerAdapter這個類,重寫這個類中的方法可以讓我們增加額外的配置,常用的有如下幾個。
自定義資源映射 addResourceHandlers
如果想自定義靜態(tài)資源映射目錄的話,只需重寫WebMvcConfigurerAdapter類的addResourceHandlers方法即可。
/**
* {@inheritDoc}
* <p>This implementation is empty.
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/illuos1ion/**").addResourceLocations("classpath:/illuos1ion/");
super.addResourceHandlers(registry);
}
/ ========================================================================================= /
// WebMvcAutoConfiguration
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if(!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Integer cachePeriod = this.resourceProperties.getCachePeriod();
if(!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(cachePeriod));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if(!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(this.resourceProperties.getStaticLocations()).setCachePeriod(cachePeriod));
}
}
}
- 通過addResourceHandler添加映射路徑,然后通過addResourceLocations來指定資源文件路徑。
- 訪問自定義illuos1ion文件夾中的 item-video.png 圖片的地址為
http://localhost:8080/illuos1ion/item-video.png
如果想指定外部的文件目錄也很簡單,直接通過addResourceLocations方法指定即可:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/my/**").addResourceLocations("file:E:/illuos1ion/");
super.addResourceHandlers(registry);
}
- addResourceLocations 指的是文件放置的目錄,addResoureHandler 指的是對外暴露的訪問路徑
頁面跳轉(zhuǎn) addViewControllers
重寫 WebMvcConfigurerAdapter 中的 addViewControllers 方法即可達(dá)到你想要的處理效果:
/**
* 過去要訪問一個頁面需要先創(chuàng)建個Controller控制類,再寫方法跳轉(zhuǎn)到頁面
* 在這里配置后就不需要那么麻煩了,直接訪問http://localhost:8080/toLogin就跳轉(zhuǎn)到login.jsp頁面了
* @param registry
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/toLogin").setViewName("login");
super.addViewControllers(registry);
}
需要注意的是,在這里重寫addViewControllers方法,并不會覆蓋WebMvcAutoConfiguration中的addViewControllers(在此方法中,Spring Boot將“/”映射至index.html),這也就意味著我們自己的配置和Spring Boot的自動配置同時有效。
攔截器addInterceptors
攔截器在項目中經(jīng)常使用的,這里介紹下最簡單的判斷是否登錄的使用。
要實現(xiàn)攔截器功能需要完成2個步驟:
- 創(chuàng)建自己的攔截器類并實現(xiàn) HandlerInterceptor 接口
- 重寫WebMvcConfigurerAdapter類中的addInterceptors方法把自定義的攔截器類添加進(jìn)來即可
攔截器代碼:
@Component
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean flag;
User user = (User) request.getSession().getAttribute("user");
if (user == null) {
response.sendRedirect("/login");
flag = false;
} else {
flag = true;
}
return flag;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
- 這里簡單實現(xiàn)了根據(jù)session中是否有User對象來判斷是否登錄,為空就跳轉(zhuǎn)到登錄頁,不為空就通過。
- 接著,重寫WebMvcConfigurerAdapter類中的addInterceptors方法:
Web配置代碼:
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter{
@Autowired
LoginInterceptor loginInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// addPathPatterns 用于添加攔截規(guī)則
// excludePathPatterns 用戶排除攔截
// 映射為 user 的控制器下的所有映射
registry.addInterceptor(loginInterceptor).addPathPatterns("/login/home").excludePathPatterns("/index", "/");
super.addInterceptors(registry);
}
}
攔截器執(zhí)行流程參考:http://www.lxweimin.com/p/f14ed6ca4e56
addPathPatterns("/login/home")
對/login/home
請求攔截,但是排除了/index
和/
請求的攔截。
Html登錄代碼:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>Login</title>
<link rel="stylesheet" href="/webjars/bootstrap/3.3.7-1/css/bootstrap.min.css"/>
<script type="text/javascript" src="/webjars/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<form class="form-horizontal" role="form" method="post" action="/login/process">
<div class="form-group">
<!--<span class="input-group-addon">用戶名</span>-->
<label class="control-label col-sm-2" for="username">用戶名:</label>
<div class="col-sm-10">
<input type="text" id="username" name="username" class="form-control" placeholder="Username"/>
</div>
</div>
<div class="form-group">
<!--<span class="input-group-addon">密碼</span>-->
<label class="control-label col-sm-2" for="password">密 碼:</label>
<div class="col-sm-10">
<input type="text" id="password" name="password" class="form-control" placeholder="Password"/>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" class="btn btn-info">登 錄</button>
<button type="submit" class="btn btn-info">注 冊</button>
</div>
</div>
</form>
</body>
</html>
控制器代碼:
@Controller
@RequestMapping(path = "/login")
public class LoginController {
@RequestMapping(path = "/process", method = RequestMethod.POST)
public String login(@RequestParam String username,
@RequestParam String password,
HttpServletRequest request) {
if (username.equals("admin") && password.equals("admin")) {
User user = new User(username, password, "http://www.jiyongguang.xin");
request.getSession().setAttribute("user", user);
return "redirect:/login/home";
}
return "redirect:/";
}
@RequestMapping(path = "/home", method = RequestMethod.GET)
public String home(Model model) {
List<User> userList = new ArrayList<User>();
User user = new User("jyg", "jyg", "http://www.jiyongguang.xin");
userList.add(user);
user = new User("lyn", "lyn", "http://www.jiyongguang.xin");
userList.add(user);
model.addAttribute("userList", userList);
return "home";
}
}
或者可以通過Jquery
封裝好的AJAX
方法來執(zhí)行一套請求。效果是一樣的
$(document).ready(function () {
$("#login").click(function () {
$.ajax({
type: "POST",
url: "/login/process",
data: {
username: $("#username").val(),
password: $("#password").val()
},
dataType: "json",
success: function (data) {
if (data.code == 1)
<!-- 當(dāng)前頁面打開URL頁面 -->
window.location.href = "/login/home";
else
alert("賬號密碼不能為空!");
}
});
});
});
控制器代碼:
@RequestMapping(value = "/process", method = RequestMethod.POST)
@ResponseBody
public String index(@RequestParam String username,
@RequestParam String password,
HttpServletRequest request) {
Map<String, Object> map = new HashMap<String, Object>();
if (username.equals("admin") && password.equals("admin")) {
User user = new User(username, password, "http://www.jiyongguang.xin");
request.getSession().setAttribute("user", user);
return JsonUtil.getJsonString(JsonUtil.REQUEST_SUCCESS);
} else {
return JsonUtil.getJsonString(JsonUtil.REQUEST_Fail, "用戶名或密碼錯誤");
}
}
這樣訪問/login/home
的時候,如果未登錄就會跳轉(zhuǎn)到login.html
頁面(注意緩存),而訪問http://localhost:8080/index
和http://localhost:8080
不會被攔截。
更多配置可以查看WebMvcConfigurerAdapter的類的API。因其是WebMvcConfigurer接口的實現(xiàn),所以WebMvcConfigurer的API方法也可以用來配置MVC。只是實現(xiàn)這個接口的話,要實現(xiàn)所有的方法,這個就比較麻煩了。所以還是推薦使用繼承WebMvcConfigurerAdapter類來處理。