springMVC的概述
MVC: Model 数据/模型 V:View视图【前端】 C:controller 控制【后端】
SpringMVC原理图:
- 向服务器发送Http request请求,请求被前端控制器(DispatcherServlet)捕获。
【在web.xml中配置】
- 前端控制器根据xml文件中的配置(或者注解)对请求的URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用处理器映射器(HandlerMapping)获得处理该请求的Handler以及Handler对应的拦截器,最后以 HandlerExecutionChain 对象的形式返回。
【在springMVC.xml中配置】
- 前端控制器根据获得的Handler,选择一个合适的处理器适配器(HandlerAdapter)去执行该Handler。
【在springMVC.xml中配置】
- 处理器适配器提取request中的模型数据,填充Handler入参,执行处理器(Handler)(也称之为Controller).
【程序员编写】
- Handler(Controller)执行完成后,向处理器适配器返回一个ModelAndView对象,处理器适配器再向前端控制器返回该ModelAndView对象(ModelAndView只是一个逻辑视图)。
【Handler方法的返回值】
- 根据返回的ModelAndView,前端控制器请求一个适合的视图解析器(ViewResolver)(必须是已经注册到Spring容器中的ViewResolver)去进行视图解析,然后视图解析器向前端控制器返回一个真正的视图View(jsp)。
【在springMVC.xml中配置】
- 前端控制器通过Model解析出ModelAndView中的参数进行解析,最终展现出完整的View并通过Http response返回给客户端。
【页面view,程序员编写】
- 将渲染结果返回给客户端
SpringMVC入门程序
新建web项目
导入框架jar包
|
<dependency> |
配置web.xml ,前端控制器DispatcherServlet
|
<?xml version="1.0" encoding="UTF-8"?> |
配置springMVC核心配置文件
springmvc-servlet.xml核心配置文件主要配置:
处理器映射器 、处理器适配器 、 视图解析器 、 [各个处理器]
|
<?xml version="1.0" encoding="UTF-8"?>
|
Handler注解开发
【1】RequestMapping注解
SpringMVC使用 @RequestMapping 注解为控制器指定可以处理哪些URL请求
•该注解在控制器的类定义及方法定义处都可标注
•类定义处:【请求根路径】
•提供初步的请求映射信息。相对于 WEB 应用的根目录
•方法处:
•提供进一步的细分映射信息。相对于类定义处的 URL。若类定义处未标注 @RequestMapping,则方法处标记的 URL 相对于WEB 应用的根目录
•DispatcherServlet 截获请求后,就通过控制器上@RequestMapping 提供的映射信息确定请求所对应的处理方法
【1】value属性
普通URL路径映射:
•多个URL路径可以映射到同一个处理器的功能处理方法:
•@RequestMapping(value={"/test1", "/user/create"})
【2】method属性
可以实现HTTP请求方法限定映射
如method={ RequestMethod.POST, RequestMethod.GET}
【3】params属性 【了解 较少使用】
要求HTTP请求数据中必须包含指定参数名(有值无值均可)才能匹配
【2】传入参数(十几种)
客户信息:
public class Customer {
private Integer id;
private String name;
private Date birthday;
private String address;
private String phone;
//setter..getter
}
【1.1】获取参数绑定方式:
- 基本数据类型(以int为例,其他类似)
必须保证传递过来的数据不能为null或”",否则会报异常。【不推荐】
- 包装类型(以Integer为例,其他类似)
对可能为空的数据,最好将参数数据类型定义成包装类型
//基本包装类型的参数:没值不会报错
//请求url: XXX/queryCustomerByID?cid=1
@RequestMapping("/queryCustomerByID")
public ModelAndView queryCustomerByID(Integer cid) {
ModelAndView mv = new ModelAndView();
Customer customer = customerService.queryCustomer(cid);
mv.addObject("customer", customer);
mv.setViewName("customer/customerInfo");
return mv;
}
详情页:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
</head>
<body>
<h2>Hello World!</h2>
<div>
<div>会员详情信息:</div>
<div> 编号:${customer.id}</div>
<div>姓名: ${customer.name}</div>
<div>生日:${customer.birthday}</div>
<div>手机:${customer.phone}</div>
<div>地址:${customer.address}</div>
</div>
</body>
</html>
3. 简单自定义POJO对象类型
//请求url: XXX/addCustomer
// 其他参数用 form表单 method=post 提交
//表单名称直接对应POJO的属性值,即:只需将对象的属性名和input的name值一一匹配即可
//日期类型默认格式: 月/日/年
@RequestMapping(value="/addCustomer",method = RequestMethod.POST)
public ModelAndView addCustomer(Customer c1) {
ModelAndView mv = new ModelAndView();
customerService.saveCustomer(customer);
mv.setViewName("success");
return mv;
}
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<title>新增用户</title>
</head>
<body>
<div>
<div>新增会员:</div>
<form action="${pageContext.request.contextPath}/addCustomer" method="post">
<div>姓名:<input type="text" name="name"/></div>
<div>生日:<input type="text" name="birthday"/></div>
<div>手机:<input type="text" name="phone"/></div>
<div>地址:<input type="text" name="address"/></div>
<input type="submit" value="提交" />
</form>
</div>
</body>
</html>
因为Date类型 因为比较常见,所以,一般可以用POJO对应的属性上增加
@DateTimeFormat(pattern = "yyyyMMdd") 注解来解决日期格式化
【也可以采用 自己定义 类型转换器 】
4 自定义复合包装对象类型:
在自定义包装类型中,增加其他java的pojo属性,解决参数传值问题
解决在复杂查询条件中,各种参数(包括同名参数)的数据绑定问题。
例如:顾客名和商品名进行查询时,他们的属性都有name。此时得用包装的pojo来解决
步骤:
【1】新增java的包装POJO
/**
* 客户和商品的POJO包装类
*/
public class CustomerProductVO {
private Customer customer;
private Product product;
//getter.. setter..
}
【2】编写Handler处理器
在方法的形参中,增加相应的pojo的参数信息
【3】jsp页面端
用户名: <input type=”text” name=”customer.name” /> <br>
商品名: <input type=”text” name=”product.name” /> <br>
5.数组绑定
步骤:
【1】编写Handler
【2】jsp页面的传参
<tr>
<td>
<input type=”checkbox” name=”ids” value=”1” />
</td>
</tr>
<tr>
<td>
<input type=”checkbox” name=”ids” value=”2” />
</td>
</tr>
....
6.List绑定
批量修改商品信息
List需要绑定在对象上,而不能直接写在Controller方法的参数中。
public class ProductList {
private List<Product> products;
//getter... setter..
}
@RequestMapping("/updateProducts")
public ModelAndView updateProducts(ProductList prods){
ModelAndView mv = new ModelAndView();
System.out.println("准备修改的信息:" + prods.getProducts().toString());
mv.setViewName("product/updateSuccess");
return mv;
}
页面信息:
<table>
<tr>
<td>商品编号</td>
<td>商品名称</td>
<td>商品价格</td>
<td>商品描述</td>
</tr>
<tbody>
<form action="${pageContext.request.contextPath}/product/updateProducts">
<tr>
<td><input type="hidden" name="products[0].id" value="1"/></td>
<td><input type="text" name="products[0].name" value="商品1"/></td>
<td><input type="text" name="products[0].price" value="20"/></td>
<td><input type="text" name="products[0].detail" value="商品详情1"/></td>
</tr>
<tr>
<td><input type="hidden" name="products[1].id" value="2"/></td>
<td><input type="text" name="products[1].name" value="商品2"/></td>
<td><input type="text" name="products[1].price" value="30"/></td>
<td><input type="text" name="products[1].detail" value="商品详情2"/></td>
</tr>
<input type="submit" value="修改提交"/>
</form>
</table>
7.Map绑定
Map最为灵活,它也需要绑定在对象上,而不能直接写在Controller方法的参数中。
public class UserMapForm {
private Map<String, User> users;
// getter.. setter..
}
@RequestMapping("sysmap.do")
public void test(UserMapForm userForm) {
for (Map.Entry<String, User> entry : userForm.getUsers().entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue().getUserName() + " - " +entry.getValue().getPassword());
}
}
表单页面:
<form action="sysmap.do" method="post">
<table>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="2"><input type="submit" value="Save" /></td>
</tr>
</tfoot>
<tbody>
<tr>
<td><input name="users['x'].username" value="aaa" /></td>
<td><input name="users['x'].password" value="bbb" /></td>
</tr>
<tr>
<td><input name="users['y'].username" value="ccc" /></td>
<td><input name="users['y'].password" value="ddd" /></td>
</tr>
<tr>
<td><input name="users['z'].username" value="eee" /></td>
<td><input name="users['z'].password" value="fff" /></td>
</tr>
</tbody>
</table>
</form>
解决参数乱码问题;
在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>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter>
<filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
返回值类型 ModelAndView
springMvc中controller中方法的返回值类型:
1.String 表示 返回视图 ;(一般建议使用String)
[可以在方法的参数中加入Model或者ModelMap 等方式 设定返回的Model数据]
单纯的String值: "前缀" + String值 + "后缀"
请求的转发: "forward:path" ; 转发不同控制器的请求:"forward:/path" ;
重定向: "redirect:/path";
2.ModelMap\Map \ Object \List \Set 表示 返回Model数据
而视图: 对应的是该请求的字符串值;一般表示只返回数据,不管视图
所以,常结合@ResponeBody 来返回json字符串
3.ModelAndView 表示 返回 视图和Model数据
【备注:一般不采用这种方式;而用第一种替代】
@RequestMapping("/test")
public ModelAndView reg(String uname){
ModelAndView mv = new ModelAndView();
mv.setViewName("MyJsp");
//mv.setView(new RedirectView("index"));
User u = new User();
u.setName(uname);
mv.addObject(u);
mv.addObject("a", "aaaa");
return mv;
}
4.void
表示 一般表示既不返回视图也不返回数据;所以,常用于文件下载;spring