概述
springmvc功能
- Controller为中心完成对系统流程的控制管理
- 从请求中搜集数据
- 对传入的参数进行验证
- 将结果返回给视图
- 针对不同的视图提供不同的解决方案
- 针对jsp视图技术提供标签库
- 拦截器
- 上传文件
springmvc结构
- DispatcherServlet:中央控制器,把请求给转发到具体的控制类
- Controller:具体处理请求的控制器(配置文件方式需要配置,注解方式不用配置)
- handlerMapping:映射处理器,负责映射中央处理器转发给controller时的映射策略
- ModelAndView:服务层返回的数据和视图层的封装类(无论是配置文件还是注解都不需要配置)
- ViewResolver & View:视图解析器,解析具体的视图
- Interceptors :拦截器,负责拦截我们定义的请求然后做处理工作(无论是配置文件方式还是注解都需要先创建再配置)
2、4、6的是需要自己创建,1、3、5是需要配置的。
mvc模式
springmvc流程
springmvc的示例
1.创建一个web工程
2.导入依赖包
3.配置web.xml
配置中央控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<!--
中央控制器
-->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<!--
区分于struts2/*, 要用*.xxx,按规范*.do
-->
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
4.配置springmvc
创建springmvc-servlet.xml文件
文件的命名规则:中央控制器(servlet的名称)的名称+“-servlet.xml”
默认位置:WEB-INF下
配置controller和视图解析器
视图解析器
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--
视图解析器前缀:从根目录开始到一个公共的目录
-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!--
视图的后缀
-->
<property name="suffix" value=".jsp"></property>
</bean>
配置controller
<!--
配置文件形式开发springmvc要配置的组件:
controller, handlerMapping(可选,不配置有默认的), ViewResovler, interceptor
-->
<bean id="testController" name="/hello.do" class="com.rl.controller.TestController"></bean>
5.创建controller
springmvc基于xml的开发(基本不会用)
三种handlerMapping(映射策略)
配置在springmvc的配置文件中
BeanNameUrlHandlerMapping(默认)
<!-- 按着controller的name来映射寻找controller,默认存在 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
SimpleUrlHandlerMapping
<!-- 使用简单url来映射 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello1.do">myController</prop>
</props>
</property>
</bean>
ControllerClassNameHandlerMapping
<!-- 控制类的类名控制器,访问时类名首字母需要小写 -->
<bean class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping"></bean>
几种控制器(controller)
ParameterizableViewController(参数控制器)
<bean name="/toIndex.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<!-- 配置你所要跳转到视图的名称 -->
<property name="viewName" value="index"></property>
</bean>
AbstractCommandController(命令控制器)
FormController(表单控制器)
- 只支持post请求方式
- 表单控制器有简单的验证功能
- 如果提交失败返回表单页面,如果提交成功就跳转到成功页面
- 有收集表单数据的功能
- 日期类型转换
springmvc基于注解的开发(常用)
注解示例
1.创建web项目
2.在springmvc的配置文件中指定注解驱动,配置扫描器
3.@controller:标识当前类是控制层的一个具体的实现
4.@requestMapping:放在方法上面用来指定某个方法的路径,当它放在类上的时候相当于命名空间需要组合方法上的requestmapping来访问。
@Controller//是让扫描器识别的注解
//@RequestMapping("/test")//理解为当前Controller的命名空间
@RequestMapping("/user/test")//理解为当前Controller的命名空间
public class TestController {
/**
*
* desc:方法名字随便定义,
* 返回值:String,指的是返回的页面的viewName,也就是ModelAndView中的viewName,也会被视图的解析器解析
* @RequestMapping:定义方法映射的地址,注解值和方法名保持一致
* author:任亮
* mail:renliangjava@163.com
* 班级:0726
*/
@RequestMapping("/hello.do")
public String hello(){
System.out.println("hello springmvc ann");
return "index";
}
}
常用注解
@Controller
是让扫描器识别的注解
@RequestMapping
这个可以放在控制器类和方法的前面,用来指定映射的路径
放在类的前面
//@RequestMapping("/test")//理解为当前Controller的命名空间
@RequestMapping("/user/test")//理解为当前Controller的命名空间
public class TestController {
放在方法的前面
/**
*
* @RequestMapping:定义方法映射的地址,注解值和方法名保持一致
*/
@RequestMapping("/hello.do")
public String hello(){
@InitBinder
这个注解用来做数据类型转换
/**
*
* desc:做数据类型转换
*/
@InitBinder
public void initBinder(ServletRequestDataBinder binder){
binder.registerCustomEditor(Date.class,
new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"), true));
}
方法中的参数
从页面接收数据的参数
页面用name属性来表示传递的参数
基本类型参数
/**
*
* desc:参数列表中直接定义要接收的参数,注意:形参变量名必须要和请求中的参数名一致才能接收
* 数据类型的定义是根据具体的业务含义来决定,只要能相互转换的数据类型就都能接收,如果参数转换出错报400,如果是时间转换错是500
*/
@RequestMapping("/recParam1.do")
public String recParam1(String name, Integer id, String address, Date birthday){
System.out.println(name);
System.out.println(id);
System.out.println(address);
System.out.println(birthday);
return "index";
}
ID:<input type="text" name="id"><br>
姓名:<input type="text" name="name"><br>
地址:<input type="text" name="address"><br>
性别:<input type="text" name="gender"><br>
生日:<input type="text" name="birthday"><br>
数组参数
/**
* 多选必须要拿数组来接收,数组的变量名favor要和页面上的Input的name一致
*/
@RequestMapping("/recParam2.do")
public String recParam2(String[] favor){
for(String f : favor){
System.out.println(f);
}
/*System.out.println(favor);*/
return "index";
}
<input type="checkbox" name="favor" value="1">篮球
<input type="checkbox" name="favor" value="2">足球
<input type="checkbox" name="favor" value="3">地球
实例类型参数
/**
*
* desc:在参数列表中直接定义要接收的实体类型,必须实体类中的属性名和表单中或者request参数名要一致,
* 无论是否传递参数springmvc都会创建person对象传进来
*/
@RequestMapping(value="/recParam3.do",method=RequestMethod.POST)
public String recParam3(Person person, User user){
System.out.println(person);
System.out.println(user);
return "index";
}
实体类
public class Person {
private Integer id;
private String name;
private String address;
private Integer gender;
private Date birthday;
/**
* @return the birthday
*/
public Date getBirthday() {
return birthday;
}
/**
* @param birthday the birthday to set
*/
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/**
* @return the address
*/
public String getAddress() {
return address;
}
/**
* @param address the address to set
*/
public void setAddress(String address) {
this.address = address;
}
/**
* @return the gender
*/
public Integer getGender() {
return gender;
}
/**
* @param gender the gender to set
*/
public void setGender(Integer gender) {
this.gender = gender;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", address=" + address
+ ", gender=" + gender + ", birthday=" + birthday + "]";
}
}
public class User {
private Integer id;
private String name;
/**
* @return the id
*/
public Integer getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(Integer id) {
this.id = id;
}
/**
* @return the name
*/
public String getName() {
return name;
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
页面
<form action="test1/recParam3.do" method="post">
ID:<input type="text" name="id"><br>
姓名:<input type="text" name="name"><br>
地址:<input type="text" name="address"><br>
性别:<input type="text" name="gender"><br>
生日:<input type="text" name="birthday"><br>
<!-- <input type="checkbox" name="favor" value="1">篮球
<input type="checkbox" name="favor" value="2">足球
<input type="checkbox" name="favor" value="3">地球 -->
<input type="submit" value="提交">
</form>
需要注意的是页面的name属性与实体类的属性名相匹配
获得servlet相关参数(HttpServletRequest,HttpServletResponse,HttpSession和PrintWriter)
在方法的参数中可以直接接收HttpServletRequest,HttpServletResponse,HttpSession和PrintWriter
/**
*
* desc:在springmvc的参数列表中直接定义HttpServletRequest就可以使用
* HttpServletRequest, HttpServletResponse, HttpSession都可以定义
*/
@RequestMapping("/recParam.do")
public String recParam(HttpServletRequest request){
String name = request.getParameter("name");
System.out.println(name);
return "index";
}
所以可以用这三个参数向页面传递数据,当然一般情况下不会用这三个参数传递数据,而是用Model传递数据
不过可以用HttpServletResponse发送json数据
需要注意的是PrintWriter基本等于HttpServletResponse的getWriter()方法,只不过PrintWriter不能处理中文
Model参数
这里的map和model都算是ModelAndView的model,都可以用来传递数据,不过不建议使用第一种
/**
*
* desc:返回值时候String,参数列表中定义map,这个map是ModelAndView中的model(千万不要认为map是接收参数的)
* 不建议使用
*/
@RequestMapping("/returnModel1.do")
public String returnModel1(Map<String, Object> map) throws ParseException{
Person p = new Person();
p.setId(1);
p.setName("zhangsan");
p.setGender(1);
p.setAddress("beijing");
p.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("2000-09-10"));
//request.setAttribute("person", p)
map.put("person", p);
return "returnPage";
}
/**
*
* desc:在参数列表中定义Model,model.addAttribute("person", p);相当于request.setAttribute("person", p)
* 建议使用
*/
@RequestMapping("/returnModel2.do")
public String returnModel2(Model model) throws ParseException{
Person p = new Person();
p.setId(1);
p.setName("zhangsan");
p.setGender(1);
p.setAddress("beijing");
p.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("2000-09-10"));
//相当于request.setAttribute("person", p)
model.addAttribute("person", p);
return "returnPage";
}
方法中的返回值
响应页面
这里的返回值就是响应的页面的名字,和视图解析器里的前缀和后缀组合起来就是访问的页面路径
@RequestMapping("/toAjax.do")
public String toAjax(){
return "ajax";
}
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--
视图解析器前缀:从根目录开始到一个公共的目录
-->
<property name="prefix" value="/WEB-INF/jsp/"></property>
<!--
视图的后缀
-->
<property name="suffix" value=".jsp"></property>
</bean>
除此之外还可以返回一个ModelAndView,第一个参数同样是页面名称,第二个参数是传递到页面的参数
/**
*
* desc:返回值设置为ModelAndView,使用ModelAndView("returnPage", map);
* 不建议使用
* author:任亮
* mail:renliangjava@163.com
* 班级:0726
*/
@RequestMapping("/returnModel.do")
public ModelAndView returnModel() throws ParseException{
Map<String,Object> map = new HashMap<String,Object>();
Person p = new Person();
p.setId(1);
p.setName("zhangsan");
p.setGender(1);
p.setAddress("beijing");
p.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse("2000-09-10"));
//request.setAttribute("person", p)
map.put("person", p);
return new ModelAndView("returnPage", map);
}
重定向
不仅仅可以定向到页面还可以重定向到另外一个方法中去
/**
* 同一个Controller内部的重定向 return "redirect:"+要重定向到的方法的@RequestMapping值
* 班级:0726
*/
@RequestMapping("/redirect.do")
public String redirect(){
return "redirect:toAjax.do";
}
@RequestMapping("/toAjax.do")
public String toAjax(){
return "ajax";
}
用redirect:重定向
,可以重定向Controller内的,还可以重定向Controller间的,需要注意重定向到Controller间的需要加上Controller命名空间
/**
* Controller之间的重定向
* return "redirect:"加上/目标Controller的命名空间+@RequestMapping值
* desc:
* author:任亮
* mail:renliangjava@163.com
* 班级:0726
*/
@RequestMapping("/redirect1.do")
public String redirect1(){
return "redirect:/test3/toAjax.do";
}
文件上传
1.引入jar包
2.配置视图解析器
3. 写上传逻辑
@Controller//是让扫描器识别的注解
@RequestMapping("/upload")//理解为当前Controller的命名空间
public class UploadController {
@RequestMapping("/uploadPic.do")
public String uploadPic(HttpServletRequest request) throws IOException{
//转换request
MultipartHttpServletRequest mr = (MultipartHttpServletRequest) request;
//获得文件
MultipartFile file = mr.getFile("pic");
//获得文件的字节数组
byte[] fbyte = file.getBytes();
//获得当前时间的最小精度,精确到三位毫秒
String fileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
//再加三位随机数
Random random = new Random();
for(int i = 0; i < 3; i++){
fileName = fileName + random.nextInt(10);
}
//获得文件的原始文件名
String oriFileName = file.getOriginalFilename();
//后缀
String suffix = oriFileName.substring(oriFileName.lastIndexOf("."));
//获得项目的部署路径
String realPath = request.getSession().getServletContext().getRealPath("/");
//组装图片的全路径
String picPath = realPath + "\\upload\\"+fileName+suffix;
//定义输出流
OutputStream out = new FileOutputStream(new File(picPath));
out.write(fbyte);
out.flush();
out.close();
return "success";
}
@RequestMapping("/toUpload.do")
public String toUpload(){
return "upload";
}
}
拦截器