参考教程:B站狂神说Java
1 使用传统模式开发
-
web.xml配置
-
servlet:DispatcherServlet,spring提供的servlet,springmvc的核心
-
init-param:springmvc配置文件
-
load-on-startup:servlet启动级别,1为与服务器同步启动
-
url-pattern:配置/,接管项目下的所有请求(过滤.jsp的请求,/*则不过滤)
-
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- springmvc-servlet.xml配置
- BeanNameUrlHandlerMapping:处理映射器
- SimpleControllerHandlerAdapter:处理适配器
- InternalResourceViewResolver:视图处理器
- prefix:视图的前缀
- suffix:视图的后缀
- 视图的路径为prefix + ViewName + suffix
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean id="/hello" class="com.ccong.controller.HelloController"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
- HelloController
public class HelloController implements Controller {
@Override
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "HelloWorld");
mv.setViewName("test");
return mv;
}
}
配置完成后,访问项目目录下的/hello即可跳转到/WEB-INF/jsp/test.jsp页面,并可以通过${msg}取出请求数据
2 springmvc原理
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v51HEcCn-1584797653523)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20200321181005591.png)]
2.1 当服务器接收到请求时,所有的请求都会经过DispatcherServlet,此时DispatcherServlet将请求交给HandlerMapping进行处理
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
2.2 HandlerMapping接受到请求后会对请求的url进行解析,同时把id为/开头的bean也封装到list中交给下一层
protected String[] determineUrlsForHandler(String beanName) {
List<String> urls = new ArrayList<>();
if (beanName.startsWith("/")) {
urls.add(beanName);
}
String[] aliases = obtainApplicationContext().getAliases(beanName);
for (String alias : aliases) {
if (alias.startsWith("/")) {
urls.add(alias);
}
}
return StringUtils.toStringArray(urls);
}
2.3 当url请求的处理与对应的Controller适配后,HandlerAdapter将会把请求交给对应的Controller的handleRequest方法处理
在这里为上面HelloController类中重写的handleRequest方法
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
return ((Controller) handler).handleRequest(request, response);
}
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
mv.addObject("msg", "HelloWorld");
mv.setViewName("test");
return mv;
}
2.4 Controller处理完请求后会结果最终返回到DispatcherServlet,然后调用视图解析器解析所指向的视图并返回
检查返回的ViewName是否为重定向或转发
protected View createView(String viewName, Locale locale) throws Exception {
if (!canHandle(viewName, locale)) {
return null;
}
// Check for special "redirect:" prefix.
if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
RedirectView view = new RedirectView(redirectUrl,
isRedirectContextRelative(), isRedirectHttp10Compatible());
String[] hosts = getRedirectHosts();
if (hosts != null) {
view.setHosts(hosts);
}
return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
}
// Check for special "forward:" prefix.
if (viewName.startsWith(FORWARD_URL_PREFIX)) {
String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
InternalResourceView view = new InternalResourceView(forwardUrl);
return applyLifecycleMethods(FORWARD_URL_PREFIX, view);
}
return super.createView(viewName, locale);
}
//拼接前缀后缀
view.setUrl(getPrefix() + viewName + getSuffix());
2.5 最终拼接到/WEB-INF/jsp/test.jsp,并返回视图
3 使用注解开发
-
web.xml同上
-
springmvc-servlet.xml
- annotation-driven:注册springmvc注解支持
- default-servlet-handler:过滤静态资源如css、js等
<context:component-scan base-package="com.ccong"/>
<mvc:annotation-driven/>
<mvc:default-servlet-handler/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
- HelloController
- @RequestMapping:匹配url请求,对匹配到的请求执行方法的内容
- 可选参数:
- Model:简化版的ModelAndView
- HttpServletRequest/response
- HttpSession
- 基本数据类型或自定义类:与请求参数同名时会自动赋值
- 返回值:String类型,返回视图名称
- 可选参数:
- @ResponseBody:配置此注解的方法返回值将不经过视图解析器,将返回值直接返回前端,常用于返回json,也可在类上添加注解@RestController代替@Controller,此时该类所有带有@xxxMapping注解的方法,返回值都将直接返回前端
- @RequestMapping:匹配url请求,对匹配到的请求执行方法的内容
@Controller
public class HelloController {
@RequestMapping("/hello")
public String test1(Model model){
model.addAttribute("msg", "HelloSpringMVC");
return "test";
}
@RequestMapping("/hello2")
@ResponseBody
public String test2(Model model){
return "HelloSpringMVC";
}
}
4 RestFul风格请求
- @GetMapping:作用同@RequestMapping,但只接受get请求
- @PostMapping:作用同@RequestMapping,但只接受post请求
- url:/请求路径/{参数1}/{参数2}
- @PathVariable:获取url中name相同的参数,如果不相同可以加入参数指定
@Controller
public class HelloController {
@GetMapping("/hello/{aa}/{b}")
public String test1(Model model, @PathVariable("aa") int a, @PathVariable int b){
model.addAttribute("msg", a + b);
return "test";
}
}
5 重定向/转发及乱码问题
if (viewName.startsWith("redirect:"))
if (viewName.startsWith("forward:"))
由上面的代码可知,只需要在返回视图的name前加上“redirect/forward:/”即可实现重定向或转发(springmvc默认为转发)
@Controller
public class HelloController {
@GetMapping("/hello")
public String test1(){
return "redirect:/test";
}
}
若跳转出现乱码,可在web.xml中加上spring提供的编码过滤器
<filter>
<filter-name>encoding</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
6 拦截器
编写自定义拦截器类实现HandlerInterceptor接口并重写需要的方法
- preHandle:在访问目标前执行
- 返回值true为放行;false为拦截,一般拦截后需转发或重定向到指定页面
- postHandle:在访问目标后执行
- afterCompletion:在前面两个方法执行后即拦截结束后执行,清理资源
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
}
在spring配置文件中注册拦截器
- mapping path:需要拦截的请求,/**为/下的所有请求
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.ccong.controller.MyIntercepter"/>
</mvc:interceptor>
</mvc:interceptors>