经过@RequestMapping 注解能够定义处理器对于请求的映射规则javascript
该注解能够注解在方法上,也能够注解在类上,但意义是不一样的css
value 属性值常以“/”开始html
一个@Controller 所注解的类中,能够定义多个处理器方法。固然,不一样的处理器方法所匹配的 URI 是不一样的java
这些不一样的 URI 被指定在注解于方法之上的@RequestMapping 的value 属性中jquery
但若这些请求具备相同的 URI 部分,则这些相同的 URI,能够被抽取到注解在类之上的@RequestMapping 的 value 属性中,此时的这个 URI 表示模块的名称程序员
URI 的请求是相对于 Web 的根目录web
下面的例子仍是在第一个程序的上面进行改写ajax
/** *@RequestMapping: * value:全部请求地址的公共部分,叫作模块名称 * 位置:放在类的上面 */ @Controller @RequestMapping(value = "/test") public class MyController { @RequestMapping(value = "/some.do") public ModelAndView doSome(){ ModelAndView mv = new ModelAndView(); mv.addObject("msg","欢迎使用springmvc"); mv.addObject("fun","执行的是doSome方法"); mv.setViewName("show"); return mv; } @RequestMapping(value = "/other.do") public ModelAndView doOther(){ ModelAndView mv = new ModelAndView(); mv.addObject("msg","欢迎使用springmvc"); mv.addObject("fun","执行的是doOther方法"); mv.setViewName("show"); return mv; } }
此时在index.jsp中spring
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <p>第一个springmvc项目</p> <p> <a href="test/some.do">发起test/some.do的请求</a> </p> <p> <a href="test/other.do">发起test/other.do的请求</a> </p> </body> </html>
也就是把请求这些请求中相同的部分添加到了类的上面,添加了@RequestMapping(value = "/test")json
对于@RequestMapping,其有一个属性 method,用于对被注解方法所处理请求的提交方式进行限制,即只有知足该method属性指定的提交方式的请求,才会执行该被注解方法
Method 属性的取值为 RequestMethod 枚举常量。经常使用的为 RequestMethod.GET 与RequestMethod.POST,分别表示提交方式的匹配规则为 GET 与 POST 提交
只要指定了处理器方法匹配的请求提交方式为 POST,则至关于指定了请求发送的方式:要么使用表单请求,要么使用 AJAX 请求。其它请求方式被禁用
固然,若不指定 method 属性,则不管是 GET 仍是 POST 提交方式,都可匹配。即对于请求的提交方式无要求
例子以下:
@Controller @RequestMapping(value = "/test") public class MyController { /** *@RequestMapping:请求映射 * 属性:method:请求的方式,它的值是RequestMethod类枚举值 */ @RequestMapping(value = "/some.do",method = RequestMethod.GET) public ModelAndView doSome(){ ModelAndView mv = new ModelAndView(); mv.addObject("msg","欢迎使用springmvc"); mv.addObject("fun","执行的是doSome方法"); mv.setViewName("show"); return mv; } /** * * 获取到请求参数 */ @RequestMapping(value = "/other.do",method = RequestMethod.POST) public ModelAndView doOther(HttpServletRequest request, HttpServletResponse response , HttpSession session){ ModelAndView mv = new ModelAndView(); mv.addObject("msg","欢迎使用springmvc,获取请求的参数:"+request.getParameter("name")); mv.addObject("fun","执行的是doOther方法"); mv.setViewName("show"); return mv; } }
在index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <p>第一个springmvc项目</p> <p> <a href="test/some.do">发起test/some.do的get请求</a> </p> <form action="test/other.do" method="post"> name:<input type="text" name="name"> <input type="submit" value="post请求other.do"> </form> </body> </html>
处理器方法能够包含如下四类参数,这些参数会在系统调用时由系统自动赋值,即程序员可在方法内直接使用
只要保证请求参数名与该请求处理方法的参数名相同便可
仍是在上面的例子中,修改index.jsp页面
<h1>提交参数给Controller</h1> <form action="test/receive.do" method="post"> 姓名:<input type="text" name="name"><br> 年龄:<input type="text" name="age"><br> <input type="submit"> </form>
而后修改处理器类
@Controller @RequestMapping(value = "/test") public class MyController { /** * 逐个接收请求参数: * 要求: 处理器(控制器)方法的形参名和请求中参数名必须一致。 * 同名的请求参数赋值给同名的形参 * * 框架接收请求参数 * 1. 使用request对象接收请求参数 * String strName = request.getParameter("name"); * String strAge = request.getParameter("age"); * 2. springmvc框架经过 DispatcherServlet 调用 MyController的doOther()方法 * 调用方法时,按名称对应,把接收的参数赋值给形参 * doOther(strName,Integer.valueOf(strAge)) * 框架会提供类型转换的功能,能把String转为 int ,long , float, double等类型。 * * 400状态码是客户端错误, 表示提交请求参数过程当中,发生了问题。 */ @RequestMapping(value = "/receive.do") public ModelAndView doOther(String name, Integer age){ // 能够直接使用name和age ModelAndView mv = new ModelAndView(); // 获取到表单中的数据 mv.addObject("myname",name); mv.addObject("myage",age); mv.setViewName("show"); return mv; } }
此时在show页面就能够的到数据了
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h1>show.jsp</h1> 这些都是从request做用域获取到的数据 <h2>姓名:${myname}</h2> <h2>年龄: ${myage}</h2> </body> </html>
请求中参数名和处理器方法的形参名不同
在index.jsp页面
<p>请求参数名和处理器方法的形参名不一致</p> <form action="test/receiveparam.do" method="post"> 姓名:<input type="text" name="username"><br> 年龄:<input type="text" name="rage"><br> <input type="submit"> </form>
主要就是处理器中方法的名字和请求参数的名字不同,这个时候须要添加注解
/** *请求中参数名和处理器方法的形参名不同 * @RequestParam:逐个解决请求中参数名和形参名不一致的问题 * 属性: * 1. value,请求中参数的名称 * 2. required 是一个boolean,默认是true * true表示请求中必须包含此参数 * 做为:在处理器方法的形参前面定义 */ @RequestMapping(value = "/receiveparam.do") public ModelAndView receiveParam(@RequestParam(value = "username") String name, @RequestParam(value = "rage") Integer age){ ModelAndView mv = new ModelAndView(); // 获取到表单中的数据 mv.addObject("myname",name); mv.addObject("myage",age); mv.setViewName("show"); return mv; }
这样就能够在show页面接收到数据了
对于前面所接收的post请求,若含有中文,则会出现中文乱码问题
Spring 对于请求参数中的中文乱码问题,给出了专门的字符集过滤器,解决方法:
在 web.xml 中注册字符集过滤器,便可解决 Spring 的请求参数的中文乱码问题
注意:最好将该过滤器注册在其它过滤器以前。由于过滤器的执行是按照其注册顺序进行的
<?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"> <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.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <!--声明过滤器,解决post请求乱码的问题--> <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> <!--强制请求对象(HttpServletRequest)使用encoding编码--> <init-param> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <!--强制请求对象(HttpServletResponse)使用encoding编码--> <init-param> <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> <!--这个过滤器基本上每一个项目都有使用,直接用便可--> </web-app>
将处理器方法的参数定义为一个对象,只要保证请求参数名与这个对象的属性同名便可
1. 定义一个Student类
package com.md.vo; /** * @author MD * @create 2020-08-12 15:33 */ // 用于保存请求的参数的 public class Student { // 属性名和请求参数名同样 private String name; private Integer age; public Student() { } public Student(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
2. 在index.jsp中
<p>使用java对象来接收请求参数</p> <form action="test/receiveobject.do" method="post"> 姓名:<input type="text" name="name"><br> 年龄:<input type="text" name="age"><br> <input type="submit"> </form>
3. 在处理器类
package com.md.controller; @Controller @RequestMapping(value = "/test") public class MyController { /** * 处理器方法形参是java对象,这个对象的属性名和请求中参数名同样 * 框架会建立形参的java对象,给属性赋值,请求中的参数是name,框架会调用setName() * */ @RequestMapping(value = "/receiveobject.do") public ModelAndView receiveObject(Student student){ ModelAndView mv = new ModelAndView(); // 获取到表单中的数据 mv.addObject("myname",student.getName()); mv.addObject("myage",student.getAge()); mv.setViewName("show"); return mv; } }
此时show页面也是能够接收到数据的
使用@Controller 注解的处理器的处理器方法,其返回值经常使用的有四种类型:
若处理器方法处理完后,须要跳转到其它资源,且又要在跳转的资源间传递数据,此时处理器方法返回 ModelAndView 比较好。固然,若要返回 ModelAndView,则处理器方法中须要定义 ModelAndView 对象。
在使用时,若该处理器方法只是进行跳转而不传递数据,或只是传递数据而并不向任何资源跳转(如对页面的 Ajax 异步响应),此时若返回 ModelAndView,则将老是有一部分多余:要么 Model 多余,要么 View 多余。即此时返回 ModelAndView 将不合适
以前的例子中一直用的就是这个
处理器方法返回的字符串能够指定逻辑视图名,经过视图解析器解析能够将其转换为物理视图地址
例如:
在index.jsp页面中
<h1>处理器方法返回String表示视图名称</h1> <form action="return-view.do" method="post"> 姓名:<input type="text" name="name"><br> 年龄:<input type="text" name="age"><br> <input type="submit"> </form>
在springmvc.xml中配置视图解析器
<!--声明springmvc框架中的视图解析器,帮助开发人员设置视图文件路径--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--前缀:视图文件的路径--> <property name="prefix" value="/WEB-INF/view/" /> <!--后缀:视图文件的扩展名--> <property name="suffix" value=".jsp"/> </bean>
在处理器中,
@Controller public class MyController { /** * 处理器方法返回String--表示逻辑视图名称,须要配置视图解析器 */ @RequestMapping(value = "/return-view.do") public String doReturnView(HttpServletRequest request,String name , Integer age){ System.out.println("doReturnView , name="+name+" "+"age="+age); // 这个时候能够本身手动的添加数据到request做用域 request.setAttribute("myname",name); request.setAttribute("myage",age); // show , 是逻辑视图名称,项目中已经配置了视图解析器 // 在这里,框架对视图执行的是转发操做 return "show"; } }
因为配置了视图解析器,此时返回字符串show,这个字符串与视图解析器中的 prefix、suffix 相结合,便可造成要访问的 URI
固然,也能够直接返回资源的物理视图名。不过,此时就不须要再在视图解析器中再配置前辍与后辍了
// 处理器方法返回的String,表示完整的视图路径, // 此时不能配置视图解析器 @RequestMapping(value = "/return-view2.do") public String doReturnView2(HttpServletRequest request,String name , Integer age){ System.out.println("---------doReturnView2--------- , name="+name+" "+"age="+age); // 这个时候能够本身手动的添加数据到request做用域 request.setAttribute("myname",name); request.setAttribute("myage",age); // show , 是逻辑视图名称,项目中已经配置了视图解析器 // 在这里,框架对视图执行的是转发操做 return "/WEB-INF/view/show.jsp"; }
处理器方法也能够返回 Object 对象。这个 Object 能够是 Integer,String,自定义对象,Map,List 等。但返回的对象不是做为逻辑视图出现的,而是做为直接在页面显示的数据出现的
返回对象,须要使用@ResponseBody 注解,将转换后的 JSON 数据放入到响应体中
因为返回 Object 数据,通常都是将数据转化为了 JSON 对象后传递给浏览器页面的。而这个由 Object 转换为 JSON,是由 Jackson 工具完成的。因此须要导入 Jackson 的相关 Jar 包
1. 在pom.xml中
<!--jackson依赖--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.0</version> </dependency>
2. 声明注解驱动
将 Object 数据转化为 JSON 数据,须要由消息转换器 HttpMessageConverter 完成。而转换器的开启,须要由<mvc:annotation-driven/>来完成。
SpringMVC 使用消息转换器实现请求数据和对象,处理器方法返回对象和响应输出之间的自动转换
在springmvc.xml中添加
<!-- 加入注解驱动 --> <!--注意:找到结尾为mvc的driven--> <mvc:annotation-driven />
返回自定义类型对象时,不能以对象的形式直接返回给客户端浏览器,而是将对象转换为 JSON 格式的数据发送给浏览器的
因为转换器底层使用了Jackson转换方式将对象转换为JSON数据,因此须要导入Jackson的相关 Jar 包
1. 定义数据类
package com.md.vo; public class Student { // 属性名和请求参数名同样 private String name; private Integer age; public Student() { } public Student(String name, Integer age) { this.name = name; this.age = age; } // set和get方法, }
修改处理器
重点看注释
package com.md.controller; @Controller public class MyController { /** * 处理器方法返回一个Student,经过框架转为json,响应ajax请求 * @ResponseBody * 做用:把处理器方法返回对象转为json后,经过HttpServletResponse输出给浏览器 * 位置:方法定义的上面 * 返回对象框架的处理流程: * 1. 框架会把返回Student类型,调用框架的中ArrayList<HttpMessageConverter>中每一个类的canWrite()方法 * 检查那个HttpMessageConverter接口的实现类能处理Student类型的数据--MappingJackson2HttpMessageConverter * * 2.框架会调用实现类的write(), MappingJackson2HttpMessageConverter的write()方法 * 把林动的student对象转为json, 调用Jackson的ObjectMapper实现转为json * contentType: application/json;charset=utf-8 * * 3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成 */ @RequestMapping(value = "/returnStudentJson.do") @ResponseBody public Student doStudentJson(String name , Integer age){ // 调用service , 获取请求结果数据,Student对象表示结果数据 Student student = new Student("林动", 20); // 会被框架转为json return student; } }
在index.jsp页面
首先把jQuery导入进来,在webapp下创建js目录,jQuery复制进来就好了
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="js/jquery-3.4.1.js"></script> <script type="text/javascript"> $(function(){ $("button").click(function(){ $.ajax({ url:"returnStudentJson.do", data:{ name:"pony", age:20 }, type:"post", dataType:"json", success:function(resp){ //resp从服务器端返回的是json格式的字符串 {"name":"林动","age":20} //jquery会把字符串转为json对象, 赋值给resp形参。 alert(resp.name + " "+resp.age); } }) }) }) </script> </head> <body> <button id="btn">发起Ajax请求</button> </body> </html>
仍是在上面的基础上,修改处理器MyController
package com.md.controller; @Controller public class MyController { /** * 处理器方法返回的是List<Student> * 处理的方式和上面的同样, */ @RequestMapping(value = "/returnStudentJsonArray.do") @ResponseBody public List<Student> doStudentJsonArray(String name , Integer age){ List<Student> list = new ArrayList<>(); // 调用service , 获取请求结果数据,Student对象表示结果数据 Student student = new Student("林动", 20); Student student1 = new Student("唐三", 20); Student student2 = new Student("白昊天", 10); list.add(student); list.add(student1); list.add(student2); // 会被框架转为json的数组 return list; } }
此时在index.jsp页面上
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="js/jquery-3.4.1.js"></script> <script type="text/javascript"> $(function(){ $("button").click(function(){ $.ajax({ url:"returnStudentJsonArray.do", data:{ name:"pony", age:20 }, type:"post", dataType:"json", success:function(resp){ [{"name":"林动","age":20},{"name":"唐三","age":20},{"name":"白昊天","age":10}] $.each(resp,function(i,n){ alert(n.name+" "+n.age) }) } }) }) }) </script> </head> <body> <button id="btn">发起Ajax请求</button> </body> </html>
这样点击按钮就能够获取到数据了
若要返回非中文字符串,将前面返回数值型数据的返回值直接修改成字符串便可。
但若返回的字符串中带有中文字符 ,则接收方页面将会出现乱码 。此时须要使用@RequestMapping 的 produces 属性指定字符集
仍是修改处理器
package com.md.controller; @Controller public class MyController { /** * 处理器方法返回的是String , String表示数据的,不是视图。 * 区分返回值String是数据,仍是视图,看有没有@ResponseBody注解 * * 若是有@ResponseBody注解,返回String就是数据,反之就是视图 * * * 默认使用“text/plain;charset=ISO-8859-1”做为contentType,致使中文有乱码, * 解决方案:给RequestMapping增长一个属性 produces, 使用这个属性指定新的contentType. * * * 返回对象框架的处理流程: * 1. 框架会把返回String类型,调用框架的中ArtrayList<HtpMessageConverter>中每一个类的canWrite()方法 * 检查那个HttpMessageConverter接口的实现类能处理String类型的数据--StringHttpMessageConverter * * 2.框架会调用实现类的write(), StringHttpMessageConverter的write()方法 * 把字符按照指定的编码处理 text/plain;charset=ISO-8859-1 * * 3.框架会调用@ResponseBody把2的结果数据输出到浏览器, ajax请求处理完成 */ // 返回的是字符串,直接输出ajax请求,并不走过滤器,必须加属性才能解决乱码问题 @RequestMapping(value = "/returnStringData.do",produces = "text/plain;charset=utf-8") @ResponseBody public String doStringData(String name, Integer age){ return "我是返回的数据"; } }
在index.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script type="text/javascript" src="js/jquery-3.4.1.js"></script> <script type="text/javascript"> $(function(){ $("button").click(function(){ $.ajax({ url:"returnStringData.do", data:{ name:"pony", age:20 }, type:"post", // 返回文本数据 dataType:"text", success:function(resp){ alert("返回的是文本数据:"+resp); } }) }) }) </script> </head> <body> <button id="btn">发起Ajax请求</button> </body> </html>
*.do
在没有特殊要求的状况下,SpringMVC 的中央调度器 DispatcherServlet 的<url-pattern/>常使用后辍匹配方式,如写为*.do 或者 *.action, *.mvc
等
能够写为/,由于 DispatcherServlet 会将向静态资源的获取请求,例如.css、.js、.jpg、.png等资源的获取请求,看成是一个普通的 Controller 请求。中央调度器会调用处理器映射器为其查找相应的处理器,固然也是找不到的,
因此在这种状况下,全部的静态资源获取请求也均会报 404 错误
例如:
在index.jsp页面中存在一个访问图片的连接,演示将<url-pattern/>写为*.do能够访问到该图片,而写为/,则没法访问,仍是在第一个例子中
1. 首先在Webapp下创建img目录,而后放一张图片
2. 而后在web.xml中
<servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 使用框架时,url-pattern能够有两种值 1. 扩展名 *.xxx , xxx是扩展名,例如:*.do,*.action等 2. 使用 "/" 当你的项目中使用了 / ,它会替代Tomcat中的default 致使全部的静态资源都给DispatcherServlet处理,而默认状况下DispatcherServlet没有处理静态资源的能力 没有控制器对象能处理静态资源的访问,静态资源(html、js、img、css)都404 静态资源访问不成,但动态资源能够访问,由于咱们的程序写了MyController控制器对象,能处理some.do --> <!--<url-pattern>*.do</url-pattern>--> <url-pattern>/</url-pattern> </servlet-mapping>
修改index.jsp页面
<img src="img/time.jpg" alt="我是静态资源">
此时图片是显示不出来的
<url-pattern/>的值并非说写为/后,静态资源就没法访问了。通过一些配置后,该问题也是能够解决的
1. 使用<mvc:default-servlet-handler/>
声 明 了 <mvc:default-servlet-handler /> 后 , springmvc 框 架 会 在 容 器 中 创 建
DefaultServletHttpRequestHandler 处理器对象。它会像一个检查员,对进入 DispatcherServlet的 URL 进行筛查,若是发现是静态资源的请求,就将该请求转由 Web 应用服务器默认的Servlet 处理。通常的服务器都有默认的 Servlet
在 Tomcat 中,有一个专门用于处理静态资源访问的 Servlet 名叫 DefaultServlet
因此,只须要在springmvc.xml中加入这个标签便可
<!-- default-servlet-handler 和 @RequestMapping注解 有冲突, 须要加入annotation-driven 解决问题--> <mvc:annotation-driven /> <!--第一种处理静态资源的方式: 须要在springmvc配置文件加入 <mvc:default-servlet-handler> 原理是: 加入这个标签后,框架会创健控制器对象DefaultServletHttpRequestHandler(相似咱们本身建立的MyController). DefaultServletHttpRequestHandler这个对象能够把接收的请求转发给 tomcat的default这个servlet。 --> <mvc:default-servlet-handler />
2. 使用<mvc:resources/>
在 Spring3.0 版本后,Spring 定义了专门用于处理静态资源访问请求的处理器ResourceHttpRequestHandler。而且添加了<mvc:resources/>标签,专门用于解决静态资源没法访问问题。须要在 springmvc 配置文件中添加以下形式的配置 :
<!--第二种处理静态资源的方式 mvc:resources 加入后框架会建立 ResourceHttpRequestHandler这个处理器对象。 让这个对象处理静态资源的访问,不依赖tomcat服务器。 mapping:访问静态资源的uri地址, 使用通配符 ** location:静态资源在你的项目中的目录位置,目录不要使用/WEB-INF/及其子目录 images/**:表示 images/time.jpg , images/user/logo.gif , images/order/history/list.png --> <mvc:resources mapping="/img/**" location="/img/" /> <mvc:resources mapping="/html/**" location="/html/" /> <mvc:resources mapping="/js/**" location="/js/" /> <!--mvc:resources和@RequestMapping有必定的冲突--> <mvc:annotation-driven /> <!--一般在webapp目录下创建static目录,把使用的静态资源都放进来,这样一句话搞定--> <!--使用一个配置语句,指定多种静态资源的访问--> <!--<mvc:resources mapping="/static/**" location="/static/" />-->