第一章 SpringMVC 概述
1.1 SpringMVC 基本说明
SpringMVC是基于spring的, 是spring中的一个模块,做web开发使用的。 springmvc 叫做spring web mvc
说明他是spring的核心技术, 做web开发,springmvc内部是使用mvc架构模式。
SpringMVC 是一个容器, 管理对象的,使用IoC核心技术。 springmvc管理界面层中的控制器对象。
SpringMVC底层也是Servlet。 以Servlet为核心, 接收请求,处理请求。 显示处理结果给用户。
处理用户的请求:
用户发起请求----SpringMVC—Spring—MyBatis–mysql数据库
1.2 SpringMVC中的核心Servlet – DispatcherServlet
DispatcherServlet 是框架一个Servlet对象。 负责接收请求, 响应处理结果。
DispatcherServlet 他的父类是HttpServlet
DispatcherServlet 也叫做前端控制器( front controller)。
SpringMVC是管理控制器对象, 原来没有SpringMVC之前使用 Servlet作为控制器对象使用。现在通过SpringMVC容器创建一种叫做控制器的对象,代替Servlet行驶控制器的角色。功能。
SpringMVC 主要使用注解的方式, 创建控制器对象, 处理请求。
<servlet> <servlet-name>myweb</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--自定义配置文件的位置--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 表示服务器tomcat创建对象的顺序, 是个整数值, 大于等于0. 数值越小,创建对象的时间越早。 --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>myweb</servlet-name> <!-- url-pattern 作用: 把一些请求交给指定的servlet处理 使用中央调度器(DispatcherServlet) 1. 使用扩展名方式, 格式 *.xxx , xxx是自定义的扩展名。 例如 *.do , *.action, *.mvc 等等. 不能使用*.jsp http://localhost:8080/myweb/some.do http://localhost:8080/myweb/user/list/queryUser.do http://localhost:8080/myweb/user/list/list.do 2. 使用斜杠 "/" --> <url-pattern>*.do</url-pattern> </servlet-mapping>
1.3 springmvc请求的处理过程
简单的处理过程:用户发起请求some.do—>Tomcat接收了请求—DispatcherServlet–分配MyController(doSome()返回mv对象)–mv显示给用户了。
省略tomcat
用户some.do--------------DispatcherServlet--------------MyController
如果使用servlet处理请求
用户发起请求--------------------没有其他对象------------------------Servlet
1.4 复习
用户发起some.do—DispatcherServlet(Servlet接收请求)—转给MyController
public class DispatcherServlet extends HttpServlet{ public void service(HttpServletRequest request, HttpServletResponse response){ if(“some.do”.equals(request.getURI())){ //从容器中获取MyController MyController c = ctx.getBean(“some”)); c.doSome(); } e lse if( “other.do”.equals(request.getURI())){ OtherController c = ctx.getBean(“other”)); c.doOther(); } } }
1.5 web开发中配置文件的说明
- web.xml 部署描述符文件 , 给服务器(tomcat)。
作用:服务器在启动的时候,读取web.xml ,根据文件中的声明创建各种对象, - 根据文件中的声明 知道 请求和servlet等对象的关系。
- 框架的配置文件, springmvc的配置文件
作用:声明框架创建的项目中的各种对象, 主要是创建Controller对象的 - 配置文件的加载顺序和功能
- tomcat服务器启动, 读取web.xml. 根据web.xml文件中的说明,创建对象。
<servlet> <servlet-name>myweb</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--自定义配置文件的位置--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 表示服务器tomcat创建对象的顺序, 是个整数值, 大于等于0. 数值越小,创建对象的时间越早。 --> <load-on-startup>1</load-on-startup> </servlet>
创建DispatcherServlet他的对象, 会执行init()方法。 在init()方法中会执行 springmvc容器对象创建
WebApplicationContext ctx = new ClassPathXmlApplicationContext(“classpath:springmvc.xml”)
springmvc框架, new ClassPathXmlApplicationContext()读取springmvc的配置文件。
<context:component-scan base-package="com.bjpowernode.controller" /> <!--声明视图解析器:帮助处理视图--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀:指定视图文件的路径--> <property name="prefix" value="/WEB-INF/view/" /> <!--后缀:视图文件的扩展名--> <property name="suffix" value=".jsp" /> </bean>
使用组件扫描器base-package=“com.bjpowernode.controller” ,遍历controller包中的所有类,MyController类, 找到这个类中的@Controller, @RequestMapping注解, 就能创建MyContoller对象。
知道some.do的请求是执行doSome()方法
以上 1, 2. 都是项目启动的过程, 没有执行任何的用户请求。
用户发起请求some.do----DispatcherServlet
DispatcherServlet里面有 WebApplicationContext 。 WebApplicationContext 里面有MyController对象。
请求some.do ,DispatcherServlet 就知道是 MyController处理的。
1.6 SpringMVC内部的执行流程
springmvc内部请求的处理过程:
用户发起请求给DispatcherServlet
DispatcherServlet把请求(request)交给了 处理器映射器。
处理器映射器: springmvc框架中的对象, 需要实现HandlerMapping接口。
映射器作用: 从springmvc容器中,获取控制器对象(MyController),把找到的控制器和拦截器对象都放到 处理器执行链对象中,保存,并返回给中央调度器。(MyController controller = ApplicationContext.getBean())
DispatcherServlet把获取到的处理器执行链中的控制器对象,交给了处理器适配器
处理器适配器:是springmvc框架中的对象, 实现HandlerAdapter接口。
适配器作用: 执行控制器的方法, 也就是执行MyController.doSome()方法。得到结果ModelAndView
DispatcherServlet把控制器执行结果mv交给了 视图解析器
视图解析器: springmvc中的对象,需要实现ViewResolver接口。
视图解析器作用: 处理视图的, 组成视图的完整路径。 能创建View类型的对象
DispatcherServlet调用View类的方法, 把Model中的数据放入到request作用域。 执行request.setAttribute(), 对视图执行forward()转发行为, request.getRequestDispather(“/show.jsp”).forward(request,response)
第二章 SpringMVC 注解式开发
2.1 @RequestMapping注解的使用。
属性: value 请求的uri地址。
位置: 1) 在方法的上面, 必须的。 2)在类的上面作为模块名称
@RequestMapping(value ="/some.do") public ModelAndView doSome(){
属性 method 请求的方式, 使用RequestMehtod类的枚举,表示请求方式
@RequestMapping(value ="/other.do",method = RequestMethod.POST) public ModelAndView doOther(){
2.2 接收请求中的参数
对应HttpServletRequest, HttpServletResponse, HttpSession 只需要在控制器方法的形参列表中,定义就可以了。框架会给参数赋值, 在控制器方法内部可以直接使用 request,response,session参数。
400 : http status , 表示客户端异常。 主要是发生在用户提交参数过程中。
接收请求中的参数: 逐个接收, 对象接收
2.2.1 逐个接收
逐个接收: 请求中的参数名和控制器方法的形参名一样。按照名称对象接收参数
<p>逐个接收请求参数</p> <form action="receive-property.do" method="post"> 姓名:<input type="text" name="name"> <br/> 年龄:<input type="text" name="age"> <br/> <input type="submit" value="提交参数"> </form>
Controller接收参数
@RequestMapping(value ="/receive-property.do") public ModelAndView doPropertyParam(String name, Integer age) {}
接收参数的问题:
- 参数最好使用包装类型。 例如Integer ,能接收空值情况, 接收的是null
- 框架可以使用String到int ,long, float, double等类型转换。
- post请求中有乱码的问题, 使用字符集过滤器。
2.2.2 CharacterEncodingFilter使用:
在web.xml 声明过滤器 <filter> <filter-name>characterEncodingFilter</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> <init-param> <!--强制请求(request)对象使用encoding的编码方式--> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <!--强制应答(response)对象使用encoding的编码方式--> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <!--强制所有请求,先经过过滤器处理--> <url-pattern>/*</url-pattern> </filter-mapping>
2.2.3 请求中参数名和形参名不一样,使用@RequestParam
/** * 逐个接收请求参数, 请求中参数名和形参名不一样 * @RequestParam : 解决名称不一样的问题 * 属性: value 请求中的参数名称 * required : boolean类型的,默认是true * true:请求中必须有此参数,没有报错。 * false:请求中可以没有此参数。 * 位置: 在形参定义的前面 */ @RequestMapping(value ="/receive-param.do") public ModelAndView doReceiveParam( @RequestParam(value = "rname",required = false) String name, @RequestParam(value = "rage",required = false) Integer age) { }
2.2.4 对象接收
对象接收: 在控制器方法的形参是java对象, 使用java对象的属性接收请求中参数值。
要求: java对象的属性名和请求中参数名一样。
例子:
*/ public class Student { // 属性名和请求中参数名一样 private String name; private Integer age; // set| get方法 } @RequestMapping("/receive-object.do") public ModelAndView doReceiveObject(Student student){ System.out.println("MyController的方法doReceiveObject="+student); ModelAndView mv = new ModelAndView(); mv.addObject("myname", student.getName()); mv.addObject("myage", student.getAge()); mv.setViewName("show"); return mv; }
2.3 控制器方法的返回值
控制器方法的返回值表示本次请求的处理结果,返回值有ModelAndView, String, void , Object
请求的处理结果包含: 数据和视图。
2.3.1 ModelAndView 数据和视图
请求的结果有数据和视图,使用ModelAndView最方便
数据:存放request作用域。
视图:执行forward转发操作
2.3.2 String 视图
框架对返回值是String,执行的是forward转发操作。
视图可以表示为完整视图路径, 或者视图的逻辑名称
@RequestMapping(value ="/return-string-view.do") public String doReturnStringView1(HttpServletRequest request,String name, Integer age) { System.out.println("执行了MyController的doReturnStringView1方法name="); //返回结果,forward,转发到show.jsp //逻辑名称, 需要配置视图解析器 return "show"; } @RequestMapping(value ="/return-string-view2.do") public String doReturnStringView2(HttpServletRequest request,String name, Integer age) { System.out.println("执行了MyController的doReturnStringView2方法name="); //完整视图路径,不能使用视图解析器 return "/WEB-INF/view/show.jsp"; }
2.3.3 void 没有数据和视图
void: 没有数据和视图, 可以使用HttpServletResponse对象输出数据,响应ajax请求。
2.3.4 Object
返回Student 表示数据,还是视图。 所以控制器方法返回对象Object, 用来响应ajax请求。
返回对象Object ,可以是List, Student , Map ,String ,Integer… 这些都是数据, 而ajax请求需要的旧是数据。 在ajax请求中,一般需要从服务器返回的是json格式的数据, 经常要处理java对象到json的转换。而且还需要输出数据响应ajax请求。 框架提供了处理 java对象到json转换, 还是数据输出工作。
2.3.4.1 HttpMessageConverter 消息转换器
HttpMessageConverter 接口,作用是 1)实现请求的数据转为java对象, 2) 把控制器方法返回的对象转为json,xml,text,二进制等不同格式的数据。
public interface HttpMessageConverter<T> { /** 作用: 检查clazz这个类型的对象,能否转为 mediaType表示的数据格式 如果能转为mediaType表示的类型, 返回true, 返回true调用read() */ boolean canRead(Class<?> clazz, @Nullable MediaType mediaType); /** 作用: 接收请求中的数据,把数据转为 clazz表示的对象 */ T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; /** 作用:检查clazz这种数据类型,能否转为mediaType表示的数据格式 */ boolean canWrite(Class<?> clazz, @Nullable MediaType mediaType); /** 作用: 把t对象,按照contentType说明的格式,把对象转为json或者xml */ void write(T t, @Nullable MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException; }
MediaType:媒体类型,表示互联网中数据的格式。例如application/json, text/html, image/gif
HttpMessageConverter 接口的实现类: MappingJackson2HttpMessageConverter : 用jackson工具库的ObjectMapper把java对象转为json数据格式 StringHttpMessageConverter : 把字符串类型的数据,进行格式转换和编码
怎么使用实现类:
框架根据控制器方法的返回类型, 自动查找使用的实现类。
@RequestMapping("/receive-object.do") public Student doReceiveObject(String name,Integer age){ System.out.println("MyController的方法doReceiveObject="); Student student = new Student(); student.setName("lisi"); student.setAge(20); return student; }
默认情况下: springmvc使用了HttpMessageConveter接口的4个实现类。包括了StringHttpMessageConverter.
需要在springmvc的配置文件,加入注解驱动的标签 mvc:annotation-driven. 加入这个标签后, springmvc项目启动后,会创建HttpMessageConveter接口的7个实现类对象,包括StringHttpMessageConverter 和 MappingJackson2HttpMessageConverter。
2.3.4.2 @ResponseBody
@ResponseBody注解的作用,就是把student转换后的json通过HttpServletResponse对象输出给浏览器。
//输出json,响应ajax response.setContentType("application/json;charset=utf-8"); PrintWriter pw = response.getWriter(); pw.println(json); pw.flush(); pw.close(); @ResponseBody注解作用就上面的代码的实现
2.3.4.3 控制器方法返回对象转为json的步骤
1)pom.xml加入jackson依赖,springmvc框架,默认处理json就是使用jackson
2)在springmvc的配置文件中,加入注解驱动的标签mvc:annotation-dirven
在控制器方法的上面加入@ResponseBody注解,表示返回值数据,输出到浏览器。
2.4 静态资源处理
访问地址:
当web.xml中DispatcherServlet的url-pattern是 *.do
http://localhost:8080/ch05_url_pattern/index.jsp tomcat
http://localhost:8080/ch05_url_pattern/js/jquery-3.4.1.js tomcat
http://localhost:8080/ch05_url_pattern/images/p1.jpg tomcat
http://localhost:8080/ch05_url_pattern/html/test.html tomcat
http://localhost:8080/ch05_url_pattern/some.do DispatcherServlet(springmvc框架)
2.4.1 tomcat的default servlet
tomcat安装目录/conf/web.xml
<servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> default 叫做默认servlet ,作用: 1.它提供静态资源的处理 2.它处理所有未映射到其他请求的请求处理
2.4.2 中央调度器设置 “/”
http://localhost:8080/ch05_url_pattern/index.jsp tomcat 成功访问
http://localhost:8080/ch05_url_pattern/js/jquery-3.4.1.js 404 没有对应的控制器对象
http://localhost:8080/ch05_url_pattern/images/p1.jpg 404 没有对应的控制器对象
http://localhost:8080/ch05_url_pattern/html/test.html 404 没有对应的控制器对象
http://localhost:8080/ch05_url_pattern/some.do 200 MyController
使用斜杠 "/" . 导致中央调度器称为了默认的default servlet。 需要处理静态资源和其他的未映射的请求。 默认中央调度器没有处理 静态资源的控制器对象, 所以静态资源都是 404 。 some.do这个请求 有MyController对象, 所以能访问。 如果项目中 , 中央调度器设置了“/” , 动态资源能访问,静态资源不能访问。 需要处理静态资源的访问工作。
2.4.3 第一种方式处理静态资源
在springmvc的配置文件加入 mvc:default-servlet-handler标签, springmvc框架会在项目运行时,加入DefaultServletHttpRequestHandler对象,让这个对象处理静态资源的访问。
<!--声明注解驱动 default-servlet-handler和@RequestMapping使用有冲突 --> <mvc:annotation-driven /> <!--声明静态资源的第一种处理方式 创建DefaultServletHttpRequestHandler处理静态资源。 DefaultServletHttpRequestHandler把接收的静态资源的地址,转发给了tomcat的default 优点: 解决方式简单 缺点: 依赖tomcat服务器提供的能力。 --> <mvc:default-servlet-handler />
2.4.4 第二种静态资源的处理方式
在springmvc配置文件中加入一个 mvc:resources标签, 框架会创建ResourceHttpRequestHandler控制器对象, 使用这个对象处理静态资源的访问。 不依赖tomcat服务器。 推荐使用的。
<!--声明注解驱动 resources和@RequestMapping使用有冲突 --> <mvc:annotation-driven /> <!--声明静态资源的第二种处理方式 mapping: 访问静态资源的uri地址, 可以使用通配符(**)。 ** : 表示任意的目录和目录和资源名称 location: 静态资源在项目中的位置, 不要使用/WEB-INF目录 --> <mvc:resources mapping="/images/**" location="/images/" /> <mvc:resources mapping="/html/**" location="/html/" /> <mvc:resources mapping="/js/**" location="/js/" /> <!--一句话设置静态资源--> <!--<mvc:resources mapping="/static/**" location="/static/" />-->