SpringMVC
- Controller
@RequestMapping定义了请求路径和方法之间的关联,方法可以非常灵活,没有特殊限制。MyController需要使用使用@Bean创建出来或者@ConponentScan出来。
@Controller
public class MyController {
@RequestMapping(value = "/my-handler-path", method = RequestMethod.GET)
public String myHandlerMethod(...) {
.....
}
}
- Model
model由Spring传入
@Controller
public class MyMvcController {
@RequestMapping(value = "/my-uri-path")
public String prepareView(Model model) {
model.addAttribute("msg", "msg-value");
.....
}
}
-
View
Generally speaking it's anything which implements org.springframework.web.servlet.View. -
ViewResolver
查找视图
下面的配置会返回/WEB-INF/views/
路径下,以jsp
结尾的视图。
@Configuration
public class MyWebConfig {
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver =
new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
-
DispatcherServlet
DispatcherServlet负责将对应的请求转发给对应的Controller,然后根据用户返回的view的名字和model,用ViewResolver找到对应的view,然后视图将model的属性赋值到view中,返回给客户端。
image -
WebApplicationInitializer
WebApplicationInitializer一般初始化DispatcherServlet和AnnotationConfigWebApplicationContext -
AnnotationConfigWebApplicationContext
AnnotationConfigWebApplicationContext除了有Spring的容器管理外,还有javax.servlet.ServletContext的实例 -
@EnableWebMvc
记得我们之前学Spring的时候有学到@Import可以引入其他的配置,@EnableWebMvc也是引入了WebMvcConfigurationSupport,该类提供了MVC的配置,该配置需要加载@Configuration注解的类上。
@EnableWebMvc对应的XML配置为<mvc:annotation-driven/>
@EnableWebMvc
@Configuration
public class MyWebConfig {
.....
}
@EnableWebMvc的类引入了DelegatingWebMvcConfiguration,是WebMvcConfigurationSupport的子类。
package org.springframework.web.servlet.config.annotation;
...
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}
DelegatingWebMvcConfiguration在setConfigurers方法中注入了WebMvcConfigurer,因此我们如果有在配置类中定义这类实例,也会注入到在里面
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
.....
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
}
-
自定义MVC配置
可以实现WebMcvConfigurer(5.0之后)/WebMvcConfigurerAdapter(5.0之前)的方法,WebMvcConfigurationSupport会在配置阶段回调这些方法。
更高级的自定义配置需要重写WebMvcConfigurationSupport或者其子类的方法 -
WebMvcConfigurerAdapter如何引入新配置的?
我们的配置类继承了WebMvcConfigurerAdapter,重写了addViewControllers方法。
@EnableWebMvc
@Configuration
public class MyWebConfig extends WebMvcConfigurerAdapter {
.....
@Override
public void addViewControllers (ViewControllerRegistry registry) {
//our customization
}
...
}
上面的配置类会被注入到DelegatingWebMvcConfiguration的configurers。
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
.....
@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {
if (!CollectionUtils.isEmpty(configurers)) {
this.configurers.addWebMvcConfigurers(configurers);
}
}
}
在配置阶段DelegatingWebMvcConfiguration会调用addViewControllers进行配置类配置。
@Configuration
public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport {
...
@Override
protected void addViewControllers(ViewControllerRegistry registry) {
this.configurers.addViewControllers(registry);
}
...
}
-
SpringServletContainerInitializer
SpringServletContainerInitializer实现了ServletContainerInitializer,这意味着SpringServletContainerInitializer的onStartup会在servlet容器启动的时候执行。 -
WebApplicationInitializer
SpringServletContainerInitializer上有注解@HandlesTypes(WebApplicationInitializer.class),这意味着SpringServletContainerInitializer的onStartup方法会执行WebApplicationInitializer类的所有onStartup方法。 -
DispatcherServlet.properties
定义了DispatcherServlet默认使用的对象或者句柄,如果没有对应的对象或者句柄,会使用这里面的。 -
@RequestMapping
@RequestMapping注解上标注了@Target(value={METHOD,TYPE}),因此可以用在方法或者类上。
元素value可以是单个字符串或者多个字符串或者类似下面的路径参数,可以匹配/users/{userId}路径
@RequestMapping("/users")
@Controller
public class UserController{
@RequestMapping("/{userId}")
public String handle(....){
....
}
}
路径参数可以被捕获到方法的输入参数
@RequestMapping("/{userId}")
public void handle(@PathVariable("userId") String userId) {
// ...
}
下面的用法中方法也要加上RequestMapping,不然会报404,@RequestMapping("")和@RequestMapping都会映射“/”路径。
@Controller
@RequestMapping("/users")
public class UserController {
@RequestMapping
public String handleAllUsersRequest(){
.....
}
}
元素method可以是RequestMethod.GET、RequestMethod.DELETE
元素params是链接问号后面的内容是否包含该元素
元素headers是HTTP协议的头元素
元素consumes是多媒体类型
- URI Patterns模式匹配
? matches one character
- matches zero or more characters
** matches zero or more directories in a path
-
@RequestParam
问号之后的请求参数
如果是map,则会包含全部的参数
@RequestParam Map<String, String> queryMap -
@RequestHeader
用法类似于@PathVariable和@RequestParam,都可以在方法中获取参数,只不过这个参数是Header里面的。而且具有以下几种通用用法:
1、参数名字相同的时候可以@RequestHeader可以省略参数
2、使用Map提取所有的Header参数
3、也可以使用@RequestHeader HttpHeaders httpHeaders提取所有的Header参数
4、自动类型转换
5、默认的元素required=true,也就是没有的时候会报400的错误
6、不同的RequestHeader并不能作为多个路径对待,但在@RequestMapping中使用header可以 -
@RequestBody
-
将参数(包括路径变量和请求参数)映射到变量的属性
将请求参数映射到Trade trade变量
/trades?buySell=buy&buyCurrency=EUR&sellCurrency=USD
public class Trade {
private String buySell;
private String buyCurrency;
private String sellCurrency;
public String getBuySell () {
return buySell;
}
public void setBuySell (String buySell) {
this.buySell = buySell;
}
.................
}
@Controller
@RequestMapping("trades")
public class TradeController {
@RequestMapping
public String handleTradeRequest (Trade trade,
Model map) {
String msg = String.format(
"trade request. buySell: %s, buyCurrency: %s, sellCurrency: %s",
trade.getBuySell(), trade.getBuyCurrency(),
trade.getSellCurrency());
map.addAttribute("msg", msg);
return "my-page";
}
将路径变量/trades/buy/EUR/USD映射到Trade trade变量
@Controller
@RequestMapping("trades")
public class TradeController {
@RequestMapping("{buySell}/{buyCurrency}/{sellCurrency}")
public String handleTradeRequest (Trade trade, Model map) {
String msg = String.format(
"trade request. buySell: %s, buyCurrency: %s, sellCurrency: %s",
trade.getBuySell(), trade.getBuyCurrency(),
trade.getSellCurrency());
map.addAttribute("msg", msg);
return "my-page";
}
}
- 使用Converter将路径变量或者请求参数转化为其他对象
使用了下面的Converter我们请求路径中的数字会转化为Trade trade变量。
public class TradeIdToTradeConverter implements Converter<String, Trade> {
private TradeService tradeService;
public TradeIdToTradeConverter (TradeService tradeService) {
this.tradeService = tradeService;
}
@Override
public Trade convert (String id) {
try {
Long tradeId = Long.valueOf(id);
return tradeService.getTradeById(tradeId);
} catch (NumberFormatException e) {
return null;
}
}
}
-
处理Cookie
1、@CookieValue
2、在HttpServletResponse中写Cookie
3、在HttpServletRequest中读Cookie
参考:https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/cookie-handling.html -
处理不一定会有的请求参数可以用Optional
@Controller
public class EmployeeController {
.............
@RequestMapping("/employee3")
@ResponseBody
public String getEmployeeByDept3 (@RequestParam("dept") Optional<String> deptName) {
return "test response for dept: " + (deptName.isPresent() ? deptName.get() :
"using default dept");
}
}
-
映射多个值到数组或者MultiValueMap
参考:https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/mapping-multi-valued-query-parameter.html -
实现Session
1、在config类中实现一个Bean制造方法,相同的Session会返回相同的元素。
@Scope(WebApplicationContext.SCOPE_SESSION)
public Visitor visitor(HttpServletRequest request){
return new Visitor(request.getRemoteAddr());
}
Controller中获取
@Controller
@RequestMapping("/trades")
public class TradeController {
@Autowired
private Provider<Visitor> visitorProvider;
@RequestMapping("/**")
public String handleRequestById (Model model, HttpServletRequest request) {
model.addAttribute("msg", "trades request, serving page " + request.getRequestURI());
visitorProvider.get()
.addPageVisited(request.getRequestURI());
return "traders-page";
}
}
2、在Controller方法中写HttpSession httpSession
3、通过@Autowired
@Component
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class VisitorInfo implements Serializable {
private String name;
private int visitCounter;
private LocalDateTime firstVisitTime;
//getters/setters
.............
}
- @ModelAttribute
Controller每个请求都会调用所有的@ModelAttribute方法,会在handler之前给model赋值,key是time,value是返回值。
@ModelAttribute("time")
public LocalDateTime getRequestTime () {
return LocalDateTime.now();
}
- @RequestAttribute
和@RequestParam的区别:
@RequestAttribute是在一个请求中,拦截器,Handler等共享的元素
@RequestParam是请求链接中的参数