本文已参与「新人创作礼」活动,一起开启掘金创作之路。
目录
1.controller类如何接收dispatcher转发的请求
一.使用SpringMVC框架的开发步骤
1.环境搭建
Step1:创建maven工程
Step2:创建web项目
Step3:集成tomcat服务器
Step4:修改pom.xml配置文件
框架就是上依赖 上配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>Pro1</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>Pro1 Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <!-- springMVC依赖--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.19</version> </dependency> <!-- servlet依赖--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> </dependencies> <build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.xml</include> <include>**/*.properties</include> </includes> </resource> </resources> </build> </project>
Step5:创建SpringMVC核心配置文件
<?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:aop="http://www.springframework.org/schema/aop" xmlns:p="http://www.springframework.org/schema/p" 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-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 添加包扫描--> <context:component-scan base-package="controller"/> <!-- 添加视图解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 配置前缀--> <property name="prefix" value="/admin/"></property> <!-- 配置后缀--> <property name="suffix" value=".jsp"></property> </bean> <!-- 将访问的请求去掉后缀--> <mvc:annotation-driven> <mvc:path-matching suffix-pattern="true" /> </mvc:annotation-driven> </beans>
Step6:修改web.xml配置文件
<?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"> <!-- 注册SpringMVC的框架,就是配置DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 读取SpringMVC核心配置文件--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- DispatcherServlet拦截的请求,只接收*.action的请求--> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>
编辑
2.请求流程
1.页面请求先经过web.xml文件查看是否有SpringMVC框架,所以要在web.xml中配置dispatcherServlet的信息,就相当于声明了这个servlet。指明这个servlet接收的请求的类型。
2.dispatcherServlet这个类也有很多初始化信息需要配置,所以SpringMVC核心配置文件中配置dispatcherServlet后,要在web.xml中加载信息。
3.初始化的信息包括要告诉dispatcher转发请求的目标对象,也就是具体转发给哪个controller类,所以要先用包扫描去创建这些类。
4.当controller类处理完请求后,还要经过dispatcher处理,则需要指明需要转发的资源,所以要标明前后缀。
二.SpringMVC框架的基本应用
1.controller类如何接收dispatcher转发的请求
由简到繁的方式来介绍controller类的注解方式。
注意controller下的类要有@Controller注解。
(0)带有注解的方法的规范
- 访问权限是public
- 方法返回值任意,以前的doGet和doPost只能是void
- 方法名称任意 不用叫doGet或者doPost
- 方法可以没有参数,如果有可以是任意类型
- 要使用@RequestMapping注解来声明一个访问的路径(名称)
(1)注解在controller类中的具体的方法上
<a href="${pageContext.request.contextPath}/demo.action">注解在方法上</a>
@Controller //spring的注解,交给spring去创建对象 public class Action { @RequestMapping(value = "/demo") public String demo(){ System.out.println("访问服务器get"); return "main";//可以跳到/admin/main.jsp页面上去 } }
通过@RequestMapping代替了之前的@WebServlet注解。
如果没有在SpringMVC下配置下面代码,则value的值需要加上后缀名。
<mvc:annotation-driven> <mvc:path-matching suffix-pattern="true" /> </mvc:annotation-driven>
(2)注解在controller类上
<a href="${pageContext.request.contextPath}/user/demo.action">注解在方法上</a>
@Controller //spring的注解,交给spring去创建对象 @RequestMapping("/user") public class Action { @RequestMapping(value = "/demo") public String demo(){ System.out.println("访问服务器get"); return "main";//可以跳到/admin/main.jsp页面上去 } }
注解到类上相当于在资源上增加了一级目录或包名。如果两个类中的方法上的@RequestMapping的值相同,转发器便不知道将请求转发给哪个controller类,此时可以在类上加注解加以区别。
(3)GET和POST请求方式的注解
请求路径相同,而请求方法不同,也可以区分具体要请求的方法
<form action="${pageContext.request.contextPath}/user/demo.action" method="get"> <input type="submit" value="get提交"> </form> <form action="${pageContext.request.contextPath}/user/demo.action" method="post"> <input type="submit" value="post提交"> </form>
@Controller //spring的注解,交给spring去创建对象 @RequestMapping("/user") public class Action { @RequestMapping(value = "/demo",method = RequestMethod.GET) public String demo(){ System.out.println("访问服务器get"); return "main";//可以跳到/admin/main.jsp页面上去 } @RequestMapping(value = "/demo",method = RequestMethod.POST) public String demo2(){ System.out.println("访问服务器post"); return "main";//可以跳到/admin/main.jsp页面上去 } }
请求的路径名相同,但是请求方式不同,也看作是请求不同的资源。
2.提交数据的五种方式
(1)方式1: 散提交数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <body> <h2>方式1</h2> <form action="${pageContext.request.contextPath}/Para1.action"> <input type="text" name="myname"> <input type="text" name="age"> <input type="submit" value="参数提交"> </form> </body> </html>
@Controller public class Para { @RequestMapping("/Para1") public String para1(String myname,int age){ System.out.println("myname:"+myname+",age:"+age); return "main"; } }
1.要求请求参数的name值要和controller类的方法中的参数名相同
2.不需要关心方法中参数的转换问题,SpringMVC会进行类型自动转换
(2)方式2: 对象封装提交
<h2>方式2</h2> <form action="${pageContext.request.contextPath}/Para2.action"> <input type="text" name="myname"> <input type="text" name="age"> <input type="submit" value="参数提交"> </form>
@RequestMapping("/Para2") public String para2(User user){ System.out.println("myname:"+user.getMyname()+",age:"+user.getAge()); return "main"; }
1.需要创建User实体类,并且实体类的属性名要和请求参数的name值相同,就可以自动创建对象。
2.实体类要有set和get方法
public class User { private String myname; private int age; public String getMyname() { return myname; } public void setMyname(String myname) { this.myname = myname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
(3)方式3: 动态占位符提交
<h2>方式3</h2> <a href="${pageContext.request.contextPath}/Para3/张三/22.action">方式三提交</a>
@RequestMapping("/Para3/{myname}/{age}") public String para3(@PathVariable("myname") String name,@PathVariable("age") int age){ System.out.println("myname:"+name+",age:"+age); return "main"; }
方式3常用于链接方式的请求。
@PathVariable先从myname这个请求参数取值,再注入到name上。
也可以只写@PathVaribale,默认这个注解里的值和上方大括号里的相同,引用时形参名字要写myname。
@RequestMapping中的大括号中的参数名可以随意取,但这个名字要么和@PathVariable的值相同,要么和形参名字相同(当不写@PathVariable的值时)。
(4)方式4: 映射名称不一致
<h2>方式4</h2> <form action="${pageContext.request.contextPath}/Para4.action"> <input type="text" name="myname"> <input type="text" name="age"> <input type="submit" value="参数提交"> </form>
@RequestMapping("/Para4") public String para4(@RequestParam("myname") String uname,@RequestParam("age") int uage){ System.out.println("myname:"+uname+",age:"+uage); return "main"; }
处理请求参数的name值和方法中的参数名不相同的情况。
注解@RequestParam先从myname这个请求参数中取值,再将值注入到uname上。
(5)方式5: 手工提交数据
<h2>方式5</h2> <form action="${pageContext.request.contextPath}/Para5.action"> <input type="text" name="myname"> <input type="text" name="age"> <input type="submit" value="参数提交"> </form>
@RequestMapping("/Para5") public String para5(HttpServletRequest request){ String myname = request.getParameter("myname"); int age = Integer.parseInt(request.getParameter("age")); System.out.println("myname:"+myname+",age:"+age); return "main"; }
这种方法就是跟之前获取参数的方式相同了。
3.处理中文乱码
当post请求时,传过来的请求参数如果是中文的话会乱码。
可以在web.xml中配置过滤器设置编码格式来处理乱码问题
<!-- 中文编码过滤器--> <filter> <filter-name>encode</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> <param-name>forceRequestEncoding</param-name> <param-value>true</param-value> </init-param> <init-param> <param-name>forceResponseEncoding</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>encode</filter-name> <!-- 拦截所有请求--> <url-pattern>/*</url-pattern> </filter-mapping>
4.controller类的方法的返回值
(1)无返回值void
一般用于Ajax请求
(2)String返回值
客户端资源的地址,自动拼接前缀后缀,还可以屏蔽自动拼接字符串,可以指定返回的路径
(3)返回基本数据类型
用户Ajax请求
返回学生集合案例
Step1:添加Jackson依赖
<!-- 添加Jackson依赖--> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> <dependency>
Step2:在webapp目录下创建js目录,添加jQuery函数库
Step3:前端发送Ajax请求
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script src="js/jquery-3.4.1.min.js"></script> </head> <body> <a href="javascript:showStu()">访问服务器返回学生集合</a> <div id="mydiv"> 等待服务器返回数据 </div> <script type="text/javascript"> function showStu() { //使用Jquery封装的Ajax方法发送请求 $.ajax({ url:"${pageContext.request.contextPath}/list.action", type:"get", dataType:"json", success: function (stuList){ var s = ""; $.each(stuList,function (i,stu){ //stu.name其实在调用getName方法,所以这个stu.name要和实体类属性相同 s+=stu.name + "---" + stu.age + "<br>"; }); //回显数据 $("#mydiv").html(s); } }); } </script> </body> </html>
Step4:后端处理Ajax请求
@Controller public class Ajax { @RequestMapping("/list") @ResponseBody //解析Ajax请求,还要在springmvc.xml中添加注解驱动 public List<Student> getList(){ List<Student> list = new ArrayList<>(); list.add(new Student("张三",18)); list.add(new Student("李四",19)); return list;//SpringMVC框架负责将集合转为json数组 } }
Step5:添加注解驱动
<mvc:annotation-driven></mvc:annotation-driven>
注意:
1.Ajax请求要加@ResponseBody注解
2.注解驱动内部还有其他属性可以更改,可以用下面代码代替上面注解驱动代码
<mvc:annotation-driven> <mvc:path-matching suffix-pattern="true" /> </mvc:annotation-driven>
- 在处理Ajax请求时,不需要视图解析器,Ajax请求哪来的回哪去
(4)返回对象类型
返回json格式的对象,自动将对象或集合转为json,使用的是Jackson工具进行转换,必须要添加Jackson依赖,一般用于Ajax请求
(5)ModelAndView
返回数据和视图对象,现在用的很少。
5.SpringMVC的四种跳转方式
(1)请求转发至页面(默认)
直接返回资源名的字符串,视图解析器会自动添加前缀和后缀
(2)请求转发至控制器
返回forward:/资源名的字符串,如"forward:/user.action"。视图解析器便不会添加前缀和后缀了。
(3)重定向至页面
返回redirect:/资源名的字符串,如"redirect:/index.jsp",视图解析器便不会添加前缀和后缀了。
(4) 重定向至控制器
返回redirect:/资源名的字符串,如"redirect:/user.action",视图解析器便不会添加前缀和后缀了。
<a href="${pageContext.request.contextPath}/jump1">请求转发页面</a> <a href="${pageContext.request.contextPath}/jump2">请求转发控制器</a> <a href="${pageContext.request.contextPath}/jump3">重定向页面</a> <a href="${pageContext.request.contextPath}/jump4">重定向控制器</a>
@Controller public class Jump { @RequestMapping("/jump1") public String jump1(){ System.out.println("请求转发页面"); return "main"; } @RequestMapping("/jump2") public String jump2(){ System.out.println("请求转发控制器"); return "forward:/other"; } @RequestMapping("/jump3") public String jump3(){ System.out.println("重定向页面"); return "redirect:/admin/main.jsp"; } @RequestMapping("/jump4") public String jump4(){ System.out.println("重定向控制器"); return "redirect:/other"; } }
@Controller public class JumoToMe { @RequestMapping("/other") public String other(){ System.out.println("跳到了other"); return "main"; } }
6.数据的传递
(1)SpringMVC默认支持的参数类型
- HttpServletRequest
- HttpServletResponse
- HttpSession
- Model
- Map
- ModelMap
1.Map,Model,ModelMap和request都一样,都使用请求作用域进行数据传递,所以服务器的跳转必须是请求转发。
2.这些参数可以直接写到方法的形参中,dispatcher就会将其对象转发进来。
3.只有请求转发才能携带数据。
(2)参数传递演示
@RequestMapping("/data") public String data(HttpServletRequest request, HttpServletResponse response, HttpSession session, Model model, Map map, ModelMap modelMap){ int a = 10; request.setAttribute("requesta",a); session.setAttribute("sessiona",a); model.addAttribute("modela",a); map.put("mapa",a); modelMap.addAttribute("modelMapa",a); return "main"; } }
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> main... ${requesta}<br> ${sessiona}<br> ${mapa}<br> ${modela}<br> ${modelMapa}<br> ${param.name}<br> </body> </html>
param代表整个请求中的参数集合,name是controller的上一个页面传递过来的参数
<a href="${pageContext.request.contextPath}/data?name=w">data</a>
三.注解驱动
编辑
在springmvc.xml中写了这行代码后,SpringMVC框架会自动注册两个bean,分别是DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter,是springmvc为@controller分发请求所必须的。
注解驱动还提供其他功能
编辑
走一遍流程图
第一个小帮手HandlerMapping去解析请求路径,可以找到访问资源的名称(去掉后缀和前缀)
第二个小帮手 HandlerAdapter根据资源的名称去创建控制器的对象,生成的方式可以是bean标签,可以是注解方式。拿到对象的时候,里面的数据都注入成功了,比如方法的参数,对象的属性等
最后的Handler就是生成的对象,也就是controller对象
接下来这个对象还会去调用业务逻辑层,数据访问层
再将数据返回到controller对象,再返回给dispatcher要转发的路径,又调用下一个小帮手,ViewResolver(当返回的是字符串的时候并且没有加forward和redirect),添加前缀和后缀
再返回到dispatcher,带着放在作用域中的数据,判断是转发到哪个页面,将数据渲染到页面上,一并交给客户端