SpringMVC入门
概述
基于spring的框架,实际上是spring的一个模块,专门做web开发的。相当于servlet的一个升级。
Spring是一个对象容器,通过iocS管理对象,使用<bean>
, 注解创建对象。springMVC就是一个Spring。
SpringMVC能够创建对象,放入到SpringMVC容器中,不过放的是控制器对象。
我们要做的是:使用@Contorller注解创建控制器对象,把对象放入到SpringMVC容器中,把创建的对象当作控制器使用。这个控制器能接受用户请求,显示处理结果,可以当作servlet来使用。
但是SpringMVC创建的并不是servlet,是一个普通类对象,但是被SpringMVC赋予了servlet的功能。
而我们知道,web开发的后台都是基于servlet的,所以springMVC中有一个servlet:DispatcherServlet。它是负责接受用户所有的请求,然后将请求转发给控制器对象进行处理。
使用
步骤:
- 加入maven依赖
- 在web.xml中注册springMVC框架的核心对象DispatcherServlet
- DispatcherServlet叫做中央调度器,也叫前端控制器,父类是HttpServlet
- 负责接受用户请求,调用控制器对象对请求进行处理,将结果返回给用户
- 创建一个发起请求的页面index.jsp
- 创建控制器类
- 在类上加@Controller注解,创建对象,并放入springmvc容器中
- 在类的方法上加上@RequestMapping注解
- 创建一个显示结果的jsp
- 创建springMVC的配置文件(和spring的配置文件一样
- 声明组件扫描器
- 声明视图解析器。帮助处理视图的。
1、加入依赖
<!-- servlet依赖 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- spring-web -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
2、web.xml中注册DispatcherServlet
<!--
声明注册springmvc的核心对象DispatcherServlet
需要在tomcat服务器启动后,创建DispatcherServlet对象的实例
因为DispatcherServlet对象创建的过程中,会自动创建springMVC容器对象
自动读取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地址一般有两种方式:1、"*.xxxx",即自定义扩展名,常用的有*.do,*.action,*.mvc
http://localhost:8080/myweb/some.do
http://localhost:8080/myweb/other.do
2、使用斜杠 /
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
3、创建一个发起请求的页面index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>请求</title>
</head>
<body>
<a href="some.do">发起some.do请求</a>
</body>
</html>
4、创建控制器类
/*创建对象,并放入容器*/
@Controller
public class MyController {
/*处理用户提交的请求:springMVC是使用方法来处理的
* 方法为自定义的,可以有多种返回值,多种参数,名称自定义
* */
/*@RequestMapping:
* 请求映射,作用是将一个请求地址和一个方法绑定在一起
* 一个请求指定一个方法处理
* 属性:value:是一个属性,表示请求的uri地址(some.do)
* value值是唯一的,不能重复。推荐“/”开头
* 可以有多个值:@RequestMapping(value = {"/some.do","/first,do"})
* 位置:可以在方法上或类上。常用在方法上。
* 特点:使用@RequestMapping注解的方法叫做处理器方法或控制器方法
* 类似于servlet的doGet、doPost
* 返回值:ModelAndView,表示本次处理的结果
* model:数据,表示本次请求返回给用户的数据
* view:视图,如jsp。
* */
@RequestMapping(value = "/some.do")
public ModelAndView doSome(){
//假设此处已经调用service处理请求了
ModelAndView modelAndView = new ModelAndView();
//向返回值中添加数据
modelAndView.addObject("msg", "hello springMVC!");
//向返回值指定视图:完整路径
//框架对视图执行的操作是请求转发操作:request.getRequestDispatcher("路径").forward(request, response);
modelAndView.setViewName("/show.jsp");
return modelAndView;
}
5、创建一个结果视图:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>show</title>
</head>
<body>
<!-- 显示 modelAndView.addObject("msg", "hello springMVC!");保存的数据 -->
<h2>msg:${msg}</h2>
</body>
</html>
6、配置springMVC配置文件,扫描注解
和spring的配置方法一样。
<context:component-scan base-package="com.wm.controller"/>
7、视图解析器
在实际开发中,一些页面时不能让用户直接访问的,必须通过网站提供的入口访问,此类情况,就可以将这些页面放入WEB-INF目录下,在WEB-INF目录下的文件时不能在浏览器直接输入地址访问的。
而此种情况下,Controller类中的modelAndView.setViewName("/show.jsp");
地址就需要修改为modelAndView.setViewName("WEB-INF/view/show.jsp");
,如果有多个页面,会发现地址名有很多冗余,前缀 WEB-INF/view/
和后缀.jsp
会大量重复,此时就需要视图解析器了。
在springMVC的配置文件中配置:
<!--组件扫描器-->
<context:component-scan base-package="com.wm.controller"/>
<!--视图解析器,帮助开发人员设置视图文件的路径-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀:视图文件的路径-->
<property name="prefix" value="/WEB-INF/view/"/>
<!--后缀:视图文件的扩展名-->
<property name="suffix" value=".jsp"/>
</bean>
同时,controller中的转发操作的路径也需要修改:
modelAndView.setViewName("show");
注解开发
value属性
上面说到,@RequestMapping
注解还可以用到类的上方,具体的用法和用在方法之上一样。
作用是:将方法之上的@RequestMapping(value="")
value中相同的前缀抽取出来。具体如下:
在这样一个类当中,两个方法的@RequestMapping(value="")
的value的前缀都有/test
前端的请求是这样的:
<a href="test/some.do">发起some.do请求</a>
<a href="test/other.do">发起other.do请求</a>
@Controller
public class MyController {
@RequestMapping(value = "/test/some.do")
public ModelAndView doSome(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "doSome");
modelAndView.setViewName("show");
return modelAndView;
}
@RequestMapping(value = "/test/other.do")
public ModelAndView doOther(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "doOther");
modelAndView.setViewName("other");
return modelAndView;
}
}
这种情况下,就可以在类的上方加入@RequestMapping
,将/test
抽取出来,方便开发
@RequestMapping(value = "/test")//像这样
@Controller
public class MyController {
@RequestMapping(value = "/some.do")
public ModelAndView doSome(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "doSome");
modelAndView.setViewName("show");
return modelAndView;
}
@RequestMapping(value = "/other.do")
public ModelAndView doOther(){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "doOther");
modelAndView.setViewName("other");
return modelAndView;
}
}
method属性
用来表示请求的方式,他的值是枚举类型的RequestMethod
类中的。
如@RequestMapping(value = "/some.do",method = RequestMethod.GET)
但是用此设置请求方式,必须保证前端的请求与其一致,否则会报错:ErrorCode 405
方法参数
HttpServletRequest request,HttpServletResponse response,HttpSession session
这些和servlet中的参数使用方法相同。
@RequestMapping(value = "/some.do",method = RequestMethod.GET)
public ModelAndView doSome(HttpServletRequest request,
HttpServletResponse response,
HttpSession session){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", "doSome");
modelAndView.setViewName("show");
return modelAndView;
}
逐个接受请求参数
前台:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>请求</title>
</head>
<body>
<form action="test/some.do" method="get">
姓名:<input type="text" name="name">
年龄:<input type="text" name="age">
<input type="submit" value="提交">
</form>
</body>
</html>
/*接受用户数据参数:逐个接受
* 要求:控制器方法的形参名必须和请求中的参数名一致,同名的请求参数赋给同盟形参
* 框架接受请求参数会:
* 1、使用request对象接收参数
* String strName = request.getParameter("name");
* String strAge = request.getParameter("age");
* 2、框架通过DispatcherServlet对象 调用MyController的doSome方法
* 调用方法时,按照名称对应,将参数赋值给方法形参
* 在调用时,框架也提供类型转换功能,将String转换为int、double、long等
*
* */
@RequestMapping(value = "/some.do")
public ModelAndView doSome(String name, int age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("age", age);
modelAndView.setViewName("show");
return modelAndView;
}
但以上代码在age参数框不输入,或填入非整数时提交的话,会出现400错误代码:400一般都是参数提交有问题
将age转换成包装类型Integer
可以解决不输入age的情况。
另外,在get请求时,中文没有乱码问题,而post请求的中文会出现乱码问题,需要使用过滤器来解决,过滤器可以自定义,也可以通过框架自带的来解决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>
<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>characterEncodingFilter</filter-name>
<!--/*表示所有页面都开启过滤-->
<url-pattern>/*</url-pattern>
</filter-mapping>
@RequestParam
在请求的过程中,请求的参数名必须要和控制器方法的形参名一致,不然就无法接收。为了解决这个问题,就有了@RequestParam
注解
/*@RequestParam:用在逐个接受参数中的。
* 属性:1、value:请求的参数名
* 2、required:boolean类型的,默认是true:表示请求中必须包含此参数
* 位置:要与请求的参数相匹配的形参之前
* */
@RequestMapping(value = "/other.do")
public ModelAndView doOther(@RequestParam(value = "myname") String name,
@RequestParam(value = "myage") int age){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", name);
modelAndView.addObject("age", age);
modelAndView.setViewName("show");
return modelAndView;
}
以对象接受参数
首先创建一个实体类
public class Student {
/*属性名要和请求参数名一致*/
private String name;
private Integer age;
//set get toString
}
/*控制器方法形参是java实体类对象,这个对象的属性名和请求的参数名要一致
* 框架会创建形参的java实体类对象,给属性赋值。如:请求中的参数name,框架会调用setName
* 类似spring的set注入
* 框架会首先调用无参构造方法,然后调用set方法给对象赋值
* */
@RequestMapping(value = "/receiveObject.do")
public ModelAndView receiveObject(Student student){
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("name", student.getName());
modelAndView.addObject("age", student.getAge());
modelAndView.addObject("student",student);
modelAndView.setViewName("show");
return modelAndView;
}
控制器方法的形参中。可以有多种类型的参数,互不干扰:
public ModelAndView receiveObject(Student student, School school, String sex){ }