目录
介绍
Spring MVC是Spring Framework的一部分,是基于Java实现MVC的轻量级Web框架。【底层是servlet】
Spring的web框架围绕DispatcherServlet[调度Servlet ]设计,DispatcherServlet的作用是将请求分发到不同的处理器
特点
- 轻量级,简单易学
- 高效,基于请求响应的MVC框架
- 与Spring兼容好,无缝结合
- 约定优于配置
- 功能强大:RESful、数据验证、格式化、本地化、主题等
- 简介灵活
执行流程
-
DispatcherServlet表示前置控制器,是整个SpringMVC的控制中心。用户发出请求,DispatcherServlet接收请求并拦截请求。
我们假设请求的url为 :http://localhost:8080/SpringMVC/hello
· 如上url拆分成三部分:
. http://localhost:8080服务器域名
. SpringMVC部署在服务器上的web站点. hello表示控制器
· 通过分析,如上url表示为:请求位于服务器localhost:8080上的SpringMVC站点的hello控制器。 -
HandlerMapping为处理器映射。DispatcherServlet调用
HandlerMapping,HandlerMapping根据请求url查找Handler. -
HandlerExecution表示具体的Handler,其主要作用是根据url查找控制器如上url被查找控制器为:hello
-
HandlerExecution将解析后的信息传递给DispatcherServlet,如解析控制器映射等
-
HandlerAdapter表示处理器适配器,其按照特定的规则去执行Handler
-
Handler让具体的Controller执行
-
Controller将具体的执行信息返回给HandlerAdapter ,如ModelAndView
-
HandlerAdapter将视图逻辑名或模型传递给DispatcherServlet
-
DispatcherServlet调用视图解析器(ViewResolver)来解析HandlerAdapter传递的逻辑视图名
-
视图解析器将解析的逻辑视图名传给DispatcherServlet
-
DispatcherServlet根据视图解析器解析的视图结果,调用具体的视图
-
最终视图呈现给用户。
可能遇到的问题
访问出现404,排查步骤
- 查看控制台输出,看下是不是缺少什么jar包
- 如果jar包存在,显示无法输出,就在IDEA的项目发布中,添加lib依赖!
- 重启Tomcat即可解决!
使用配置步骤
配置版
1、新建一个Moudle,添加web的支持!
2、确定导入了SpringMVC的依赖!
3、配置web.xml,注册DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置DispatcherServlet:这个是SpringMVC的核心:请求分发器,前端控制器-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--DispatcherServlet要绑定SpringMVC的配置文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc-servlet.xml</param-value>
</init-param>
<!--启动级别:1-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<!--
在SpringMVC中,
/ :只匹配所有的请求,不会去匹配jsp页面
/* :匹配所有的请求,包括jsp页面
-->
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
4、 编写SpringMVC的配置文件!名称: spring mvc-servlet.xml : [servletname]-servlet.xml说明,这里的名称要求是按照官方来的
5、添加处理映射器
6、添加处理器适配器
7、添加视图解析器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--处理器映射器-->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<!--处理器适配器-->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<!--视图解析器:模板引擎 Thymeleaf Freemarker-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
8、编写我们要操作业务Controller,要么实现Controller接口,要么增加注解;需要返回一个ModeiAndView,装数据,封视图;
public class HelloController implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
ModelAndView mv = new ModelAndView();
//业务代码
String result = "HelloSpringMVC";
mv.addObject("msg",result);
//视图跳转
mv.setViewName("test");
return mv;
}
}
9、将自己的类交给SpringIOC容器,注册bean
<!--BeanNameUrlHandlerMapping:bean-->
<bean id="/hello" class="com.yf.controller.HelloController"/>
10、写要跳转的jsp页面,显示ModelandView存放的数据,以及我们的正常页面:
注解版
1、配置web.xml文件【具体流程和上面配置版类似】
注意点
注意web.xml版本问题,要最新版!
注册DispatcherServlet
关联SpringMVC的配置文件
启动级别为1
映射路径为/【不要用/*,会404】
2、添加SpringMVC配置文件【springmvc-servlet.xml】
- 让IOC的注解生效
- 静态资源过滤:HTML . JS . CSS .图片,视频…
- MVC的注解驱动
- 配置视图解析器
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--自动扫描包,让指定包下的注解生效,由IOC容器统一管理-->
<context:component-scan base-package="com.yf.controller"/>
<!--让Spring MVC不处理静态资源 .css .js .html .mp4-->
<mvc:default-servlet-handler/>
<!--
支持mvc注解驱动
在spring中一般采川@RequestMapping注解来完成映射关系
要想使@RequestMapping注解生效
必须向上下文中注册DefauLtAnnotationHandLerMapping
和一个AnnotationMethodHandLerAdapter实倾
这两个实例分别在类级别和方法级别处理。
而annotation-driven配置帮助我们自动完成上述两个实例的注入。
-->
<mvc:annotation-driven/>
<!--视图解析器:模板引擎 Thymeleaf Freemarker-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver">
<!--前缀-->
<property name="prefix" value="/WEB-INF/jsp/"/>
<!--后缀-->
<property name="suffix" value=".jsp"/>
</bean>
</beans>
3、创建Controller
@Controller
@RequestMapping("/HelloController")
public class HelloController {
//真实访问地址:项目名/HelloController/hello
@RequestMapping("/hello")
public String Hello(Model model){
//封装数据,可以在]SP页面中取出并渲染
model.addAttribute("msg","Hello,SpringMVCAnnotation!");
//WEB-INF/jsp/hello.jsp
return "hello";//会被视图解析器处理,拼接
}
}
- @Controller是为了让Spring IOC容器初始化时自动扫描到;
- @RequestMapping是为了映射请求路径,这里因为类与方法上都有映射所以访问时应该是/HelloController/hello;
- 方法中声明Model类型的参数是为了把Action中的数据带到视图中;
- 方法返回的结果是视图的名称hello,加上配置文件中的前后缀变成WEB-INF/jsp/hello.jsp
RestFul风格
Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
使用
1、在新建—个类RestFulController
2、在Spring MVC中可以使用@PathVariable注解,让方法参数的值对应绑定到一个URI模板变量上。
方法级别的注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@Patchapping
@Controller
public class RestFulContoller {
//原来的: http://Localhost:8080/ add?a=1&b=2
//RestFul: http://LocaLhost:8080/add/a/b
//两种方式
//@RequestMapping(value = "/add/{a}/{b}",method=RequestMethod.GET)
@GetMapping("/add/{a}/{b}")
public String test(@PathVariable int a,@PathVariable int b, Model model){
int res=a+b;
model.addAttribute("msg","结果为"+res);
return "hello";
}
}
ModelAndVeiw
设置ModelAndView对象,根据view的名称,和视图解析器跳到指定的页面
页面:{视图解析器前缀} + viewName +{视图解析器后缀}
前端传参
当前端传递过来的参数名与字段不一致时
可以使用@RequestParam(“前端名”)的方式,或者使用RestFul风格加参数
@RequestMapping("/t1/{username}")
//普通方法@RequestParam("username")
public String test1( @PathVariable("username") String name, Model model){
//1.接收前端参数
System.out.println("参数为:"+name);
//2.将返回的结果传递给前端,Model
model.addAttribute("msg",name);
//3.视图跳转
return "test";
}
传递对象
1.接收前端用户传递的参数,判断参数的名字,假设名字直接在方法上,可以直接使用
2.假设传递的是一个对象User,匹配User对象中的字段名;如果名字一致则oK,否则,匹配不到显示null
//前端接收的是一个对象:id,name,age
@GetMapping("/t2")
public String test2(User user){
System.out.println(user);
return "test";
}
SpringMVC实现转发和重定向
有视图解析器
@Controller
public class ForwardAndRedirect {
@RequestMapping("/forward")
public String test(Model model){
model.addAttribute("msg","forwardTest");
return "hello";
}
@RequestMapping("/redirect")
public String test1(Model model){
model.addAttribute("msg","redirectTest");
return "redirect:/index.jsp";
}
}
无视图解析器:【不推荐】
@Controller
public class ForwardAndRedirect {
@RequestMapping("/forward")
public String test(Model model){
model.addAttribute("msg","forwardTest");
return "forward:WEB-INF/jsp/hello.jsp";
}
@RequestMapping("/redirect")
public String test1(Model model){
model.addAttribute("msg","redirectTest");
return "redirect:/index.jsp";
}
}
乱码问题
在POST的传值存在乱码的情况,SpringMVC有自带的过滤器为我们解决此类问题,只需在web.xml中配置一下
<!--配置SpringMVC的乱码问题-->
<filter>
<filter-name>encodingFilter</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>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
但有可能在使用GET方式时出现问题,所以在网上查找到一个大佬手写的过滤器
public class GenericEncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
// 处到response的字符编码
HttpServletResponse myResponse=(HttpServletResponse) resp;myResponse.setContentType("text/html; charset=UTF-8");
// 转型为与协议相关对象
HttpServletRequest httpServletRequest = (HttpServletRequest) req;
// 对request包装增强
HttpServletRequest myrequest = new MyRequest(httpServletRequest);
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
//自定义request对象,HttpServletRequest的包装类
class MyRequest extends HttpServletRequestWrapper {
private HttpServletRequest request;
//是香编码的标记
private boolean hasEncode;
//定义一个可以传入HttpServLetRequest对象的构造函数,以便对其进行装饰
public MyRequest(HttpServletRequest request) {
super(request);// super必须写
this.request = request;
}
//对需要增强方法进行覆盖
@Override
public Map getParameterMap( ) {
//先获得请求方式
String method = request.getMethod();
if (method.equalsIgnoreCase("post")) {
// post请求
try {
//处到post乱码
request.setCharacterEncoding("utf-8");
return request.getParameterMap();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} else if (method.equalsIgnoreCase("get")) {
// get请求
Map<String, String[]> parameterMap = request.getParameterMap();
if (!hasEncode) {//确保get手动编码逻辑只运行一次
for (String parameterName : parameterMap.keySet()) {
String[] values = parameterMap.get(parameterName);
if (values != null) {
for (int i = 0; i < values.length; i++) {
try {
//处型get乱码
values[i] = new String(values[i].getBytes("Iso-8859-1"), "utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
}
hasEncode = true;
}
return parameterMap;
}
return super.getParameterMap();
}
//取一个值
@Override
public String getParameter(String name) {
Map<String,String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
if (values == null){
return null;
}
return values[0]; //取回参数的第一个值
}
//取所有值
@Override
public String[] getParameterValues(String name) {
Map<String, String[]> parameterMap = getParameterMap();
String[] values = parameterMap.get(name);
return values;
}
}
拦截器
- 拦截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 拦截器只会拦截访问的控制器方法,如果访问的是jsp/html/css/image/js是不会进行拦截的
使用
自定义一个拦截器,必须实现 Handlerlnterceptor接口。
public class Mylnterceptor implements HandlerInterceptor {
//return true; 执行下一个拦截器
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("=====处理前=====");
return false;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("=====处理后=====");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("=====清理=====");
}
}
在applicationContext.xml中配置拦截器
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<!--包含这个路径下的所有请求-->
<mvc:mapping path="/**"/>
<bean class="com.yf.config.Mylnterceptor"/>
</mvc:interceptor>
</mvc:interceptors>