1. 新增编辑页
1). 在WebContent/WEB-INF/jsp/目录下创建editItem.jsp文件
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改商品信息</title>
</head>
<body>
<!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
<!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->
<form id="itemForm" action="${pageContext.request.contextPath }/updateItem.action" method="post">
<input type="hidden" name="id" value="${item.id }"/>修改商品信息:
<table width="100%" border="1">
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${item.name }"/></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${item.price }"/></td>
</tr>
<tr>
<td>商品简介</td>
<td><textarea rows="3" cols="30" name="detail">${item.detail}</textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>
2). Item类
public class Item {
// 编号
private Integer id;
// 商品名称
private String name;
// 价格
private Float price;
// 图片
private String pic;
// 描述
private String detail;
// 时间戳
private Timestamp createtime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public String getPic() {
return pic;
}
public void setPic(String pic) {
this.pic = pic;
}
public Timestamp getCreatetime() {
return createtime;
}
public void setCreatetime(Timestamp createtime) {
this.createtime = createtime;
}
public String getDetail() {
return detail;
}
public void setDetail(String detail) {
this.detail = detail;
}
@Override
public String toString() {
return "Item [id=" + id + ", name=" + name + ", price=" + price + ", pic=" + pic + ", detail=" + detail
+ ", createtime=" + createtime + "]";
}
}
3). 在ItemController类中添加方法
// 标记为控制器
@Controller
public class ItemController {
// 注入Service
@Autowired
ItemService service;
// 设置网络访问路径/itemEdit.action
@RequestMapping("itemEdit")
public ModelAndView editItem(HttpServletRequest request) {
// 从request中取出参数
String strId = request.getParameter("id");
int id = Integer.valueOf(strId);
// 调用服务
Item item = service.getItemById(id);
// 把结果传递给页面
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("item", item);
// 设置逻辑视图
modelAndView.setViewName("editItem");
return modelAndView;
}
}
4). 在ItemService中创建getItemById方法
public interface ItemService {
/**
* 获取商品信息
* @param id id
* @return
*/
Item getItemById(int id);
}
5). 在ItemServiceImpl类中实现getItemById方法
// 标记为Service
@Service
public class ItemServiceImpl implements ItemService {
// 注入ItemMapper
@Autowired
ItemMapper mapper;
@Override
public Item getItemById(int id) {
return mapper.getItemId(id);
}
}
6). 在ItemMapper接口中创建getItemId方法
public interface ItemMapper {
/**
* 根据id获取商品信息
* @param id id
* @return
*/
Item getItemId(int id);
}
7). 在ItemMapper.xml文件中添加查询语句
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mazaiting.mapper.ItemMapper">
<select id="getItemId" parameterType="int" resultType="Item">
select * from items where id = #{id}
</select>
</mapper>
8). 在test源码包下添加测试方法进行测试
- ItemMapperTest.java
public class ItemMapperTest {
ApplicationContext context;
ItemMapper mapper;
@Before
public void init(){
context = new ClassPathXmlApplicationContext(Constant.PATHS);
mapper = context.getBean(ItemMapper.class);
}
@Test
public void testGetItemId(){
Item item = mapper.getItemId(1);
System.out.println(item.toString());
}
}
- ItemServiceTest
public class ItemServcieTest {
ApplicationContext context;
ItemService service;
@Before
public void init() {
context = new ClassPathXmlApplicationContext(Constant.PATHS);
service = context.getBean(ItemService.class);
}
@Test
public void testGetItemById(){
Item item = service.getItemById(1);
System.out.println(item.toString());
}
}
9). 运行项目测试(请在以上测试代码成功打印数据之后进行项目整体的测试,否则浪费时间)
2.SpringMVC框架默认支持的参数类型
处理器形参中添加如下类型的参数,处理适配器会默认识别并进行赋值。
- HttpServletRequest:通过request对象获取请求信息。
- HttpServletResponse:通过response处理响应信息。
- HttpSession:通过session对象得到session中存放的对象。
- Model/ModelMap:ModelMap是Model接口的实现类,我们可通过Model或ModelMap向页面传递数据
Items items = itemService.getItemById(id);
model.addAttribute("item", items);
页面中通过${item.XXXX}获取item对象的属性值。
3. 简单数据类型绑定
将editItem方法修改如下:
@RequestMapping("/itemEdit")
public String editItem(Integer id,Model model) {
// 调用服务
Item item = service.getItemById(id);
// 把数据传递给页面,需要用到Model接口
model.addAttribute("item", item);
return "editItem";
}
4. 支持的数据类型
SpringMVC框架支持的数据类型有:
- 整形:Integer、int
- 字符串:String
- 单精度:Float、float
- 双精度:Double、double
- 布尔型:Boolean、boolean
说明:对于布尔类型的参数,请求的参数值为true或false。处理器方法可是这样的:
public String editItem(Model model,Integer id,Boolean status) throws Exception {
...
}
至于请求的url,可是http://localhost:8080/xxx.action?id=2&status=false
注意:参数类型推荐使用包装数据类型,因为基础数据类型不可以为null。
5. @RequestParam
使用@RequestParam注解常用于处理简单类型的绑定。
value:参数名字,即入参的请求参数名字,如value=“item_id”表示请求的参数区中的名字为item_id的参数的值将传入。
-
required:是否必须,默认是true,表示请求中一定要有相应的参数,否则将报如下错误:
defaultValue:默认值,表示如果请求中没有同名参数时的默认值。
修改方法为:
// defaultValue为默认值
// required表示此参数不能为空
@RequestMapping("/itemEdit")
public String editItem(@RequestParam(value="id",defaultValue="1",required=true) Integer ids,Model model) {
// 调用服务
Item item = service.getItemById(ids);
// 把数据传递给页面,需要用到Model接口
model.addAttribute("item", item);
return "editItem";
}
6. 绑定pojo类型
1). 在ItemController中创建/updateItem.action
处理方法
// 标记为控制器
@Controller
public class ItemController {
// 注入Service
@Autowired
ItemService service;
@RequestMapping("/updateItem")
public String updateItem(Item item) {
service.updateItem(item);
// 返回成功页面
return "success";
}
}
2). 在ItemService中创建方法,并在ItemServiceImple中实现该方法
- ItemService
public interface ItemService {
/**
* 更新条目
* @param item Java Bean
*/
void updateItem(Item item);
}
- ItemServiceImpl
// 标记为Service
@Service
public class ItemServiceImpl implements ItemService {
// 注入ItemMapper
@Autowired
ItemMapper mapper;
@Override
public void updateItem(Item item) {
mapper.updateItem(item);
}
}
3). 在ItemMapper接口中添加方法并在ItemMapper.xml文件中添加查询语句
- ItemMapper
public interface ItemMapper {
/**
* 更新数据
* @param item
* @return
*/
void updateItem(Item item);
}
- ItemMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mazaiting.mapper.ItemMapper">
<update id="updateItem" parameterType="Item">
update items set name=#{name}, price=#{price}, detail=#{detail} where id = #{id}
</update>
</mapper>
4). 编写测试代码
- ItemMapperTest
public class ItemMapperTest {
ApplicationContext context;
ItemMapper mapper;
@Before
public void init(){
context = new ClassPathXmlApplicationContext(Constant.PATHS);
mapper = context.getBean(ItemMapper.class);
}
@Test
public void testUpdateItem(){
Item item = new Item();
item.setId(1);
item.setName("小米");
item.setDetail("智能手机");
item.setPrice(200.0f);
mapper.updateItem(item);
}
}
- ItemServiceTest
public class ItemServcieTest {
ApplicationContext context;
ItemService service;
@Before
public void init() {
context = new ClassPathXmlApplicationContext(Constant.PATHS);
service = context.getBean(ItemService.class);
}
@Test
public void testUpdateItem(){
Item item = new Item();
item.setId(1);
item.setName("小米4c");
item.setDetail("智能手机");
item.setPrice(200.0f);
service.updateItem(item);
}
}
5). 创建success.jsp文件
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Success</title>
</head>
<body>
<h1>更新成功</h1>
</body>
</html>
6). 测试
修改商品简介后点击提交
访问
http://localhost:8080/Ssm/itemList.action
7. 自定义参数绑定
1). 修改editItem.jsp如下
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>修改商品信息</title>
</head>
<body>
<!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
<!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->
<form id="itemForm" action="${pageContext.request.contextPath }/updateItem.action" method="post">
<input type="hidden" name="id" value="${item.id }"/>修改商品信息:
<table width="100%" border="1">
<tr>
<td>商品名称</td>
<td><input type="text" name="name" value="${item.name }"/></td>
</tr>
<tr>
<td>商品价格</td>
<td><input type="text" name="price" value="${item.price }"/></td>
</tr>
<tr>
<td>商品生产日期</td>
<td><input type="text" name="createtime"
value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/>
</td>
</tr>
<tr>
<td>商品简介</td>
<td><textarea rows="3" cols="30" name="detail">${item.detail }</textarea></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"/>
</td>
</tr>
</table>
</form>
</body>
</html>
2). 此时修改时间提交,会出现400的异常
3). 自定义Converter
在com.mazaiting.convert包下创建DateConverter类
/**
* SpringMVC转换器
* Converter<S, T> S:source源数据类型,T:target目标数据类型
* @author mazaiting
*/
public class DateConverter implements Converter<String, Date>{
@Override
public Date convert(String source) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
try {
Date date = formatter.parse(source);
return date;
} catch (ParseException e) {
e.printStackTrace();
}
return null;
}
}
4). 配置Converter
在springmvc.xml配置文件中添加如下配置:
<?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: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-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!-- 配置注解驱动,如果配置此标签,则不用配置处理器映射器和处理器适配器 -->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 转换器配置 -->
<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="com.mazaiting.converter.DateConverter"/>
</set>
</property>
</bean>
</beans>
5). 测试点击页面之后不再发生错误。虽然提交成功,但时间查询后发现没有改变,原因是我们在更新数据的时候并没有更新时间。
8. 绑定数组
1). 修改itemList.jsp
在每个条目之前增加一个checkbox。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查询商品列表</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/item/queryitem.action" method="post">
查询条件:
<table width="100%" border="1">
<tr>
<td>商品id:<input type="text" name="item.id" /></td>
<td>商品名称:<input type="text" name="item.name" /></td>
<td><input type="submit" value="查询"/></td>
</tr>
</table>
商品列表:
<table width="100%" border="1">
<tr>
<td>选择</td>
<td>商品名称</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemList }" var="item">
<tr>
<td><input type="checkbox" name="ids" value="${item.id }"/></td>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime }" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
2). 创建包装类
public class QueryVo {
private Item item;
private String[] ids;
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public String[] getIds() {
return ids;
}
public void setIds(String[] ids) {
this.ids = ids;
}
}
3). ItemController类中添加方法
@RequestMapping("item/queryitem")
public String queryitem(QueryVo queryVo, String[] ids){
// 打印绑定结果
System.out.println(ids.toString());
System.out.println(queryVo.getIds().toString());
System.out.println(queryVo.getItem().toString());
return "success";
}
9. 表单的数据绑定到List
1). 修改QueryVo类
public class QueryVo {
private Item item;
private String[] ids;
private List<Item> itemList;
public Item getItem() {
return item;
}
public void setItem(Item item) {
this.item = item;
}
public String[] getIds() {
return ids;
}
public void setIds(String[] ids) {
this.ids = ids;
}
public List<Item> getItemList() {
return itemList;
}
public void setItemList(List<Item> itemList) {
this.itemList = itemList;
}
}
2). 修改itemList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查询商品列表</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/item/queryitem.action" method="post">
查询条件:
<table width="100%" border="1">
<tr>
<td>商品id:<input type="text" name="item.id" /></td>
<td>商品名称:<input type="text" name="item.name" /></td>
<td><input type="submit" value="查询"/></td>
</tr>
</table>
商品列表:
<table width="100%" border="1">
<tr>
<td>选择</td>
<td>商品名称</td>
<td>商品价格</td>
<td>生产日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemList }" var="item" varStatus="s">
<%-- <tr>
<td><input type="checkbox" name="ids" value="${item.id }"/></td>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime }" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
</tr> --%>
<td><input type="checkbox" name="ids" value="${item.id }"/></td>
<td>
<input type="hidden" name="itemList[${s.index }].id" value="${item.id }"/>
<input type="text" name="itemList[${s.index }].name" value="${item.name }"/>
</td>
<td><input type="text" name="itemList[${s.index }].price" value="${item.price }"/></td>
<td><input type="text" name="itemList[${s.index }].createtime" value='<fmt:formatDate value="${item.createtime }" pattern="yyyy-MM-dd HH:mm:ss"/>'/></td>
<td><input type="text" name="itemList[${s.index }].detail" value="${item.detail }"/></td>
</c:forEach>
</table>
</form>
</body>
</html>
<c:forEach>标签中的varStatus属性常用参数总结如下:
- ${status.index}:输出行号,从0开始。
- ${status.count}:输出行号,从1开始。
- ${status.current}:当前这次迭代的(集合中的)项。
- ${status.first}:判断当前项是否为集合中的第一项,返回值为true或false。
- ${status.last}:判断当前项是否为集合中的最后一项,返回值为true或false。
- begin、end、step分别表示:起始序号,结束序号,跳跃步伐。
10. other
1). @RequestMapping注解的使用
@RequestMapping(value="/updateitem",method={RequestMethod.GET})
- value:指定访问路经
- method:限定请求方法
2). request转向页面
// 如果使用原始的方式做页面跳转,必须给的是jsp的完整路径
request.getRequestDispatcher("/WEB-INF/jsp/itemList.jsp").forward(request, response);
3). response重定向
response.sendRedirect("url")
4). 返回响应结果
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
5). Controller类中重定向
@RequestMapping("/updateItem")
public String updateItem(Item item) {
service.updateItem(item);
// 重定向
return "redirect:/itemList.action";
}
6). Controller类forward转发
@RequestMapping(value="/updateitem",method={RequestMethod.POST,RequestMethod.GET})
public String updateItems(Items items) throws UnsupportedEncodingException {
itemService.updateItem(items);
return "forward:/item/itemList.action";
}
11. 异常处理
系统中异常包括两类:预期异常和运行时异常(RuntimeException),前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异常的发生。系统的dao、service、controller出现异常都通过throws Exception向上抛出,最后由SpringMVC前端控制器交由异常处理器进行异常处理,SpringMVC提供全局异常处理器(一个系统只有一个异常处理器)进行统一异常处理。
1). 异常处理器
全局异常处理器处理思路:
- 解析出异常类型。
- 如果该异常类型是系统自定义的异常,直接取出异常信息,在错误页面展示。
- 如果该异常类型不是系统自定义的异常,那么应取出错误的堆栈信息,并记录下来,在错误页面展示。
SpringMVC提供一个HandlerExceptionResolver接口,自定义全局异常处理器必须要实现这个接口,所以我们可在com.mazaiting.exception包下编写一个自定义全局异常处理器。
2). 自定义一个异常类--CustomerException
/**
* 自定义异常
* @author mazaiting
*/
public class CustomerException extends Exception{
private String msg;
public CustomerException() {}
public CustomerException(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
3). 自定义异常处理器
/**
* 全局异常处理
* @author mazaiting
*/
public class GlobalExceptionResolver implements HandlerExceptionResolver{
@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler,
Exception exception) {
// 判断异常的种类
String msg = null;
if (exception instanceof CustomerException) {
// 如果是自定义异常,就从异常里面取出错误消息
CustomerException customerException = (CustomerException) exception;
msg = customerException.getMsg();
} else {
// 如果是运行时异常,则取出错误的堆栈信息, 向控制台上打印堆栈信息
exception.printStackTrace();
StringWriter writer = new StringWriter();
PrintWriter printWriter = new PrintWriter(writer);
exception.printStackTrace(printWriter);
msg = writer.toString();
}
// 写日志,发短信,发邮件。。。
// 返回一个友好的错误页面,并显示错误信息
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("msg", msg);
modelAndView.setViewName("error");
return modelAndView;
}
}
4). 创建错误页面
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>错误页面</title>
</head>
<body>
<h1>系统发送异常了。。。。。。。。。。</h1>
<br>
<h2>错误消息为:</h2>
<br>
${msg }
</body>
</html>
5). 在springmvc.xml文件中配置全局异常处理器
<!-- 配置全局异常处理器 -->
<bean class="com.mazaiting.exception.GlobalExceptionResolver"/>
6). 测试
修改方法:
// 设置网络访问路径/itemList.action
@RequestMapping("/itemList")
public ModelAndView itemList() throws CustomerException {
if (true) {
throw new CustomerException("异常啦");
}
List<Item> list = service.getItemList();
ModelAndView modelAndView = new ModelAndView();
// 设置数据
modelAndView.addObject("itemList", list);
// 设置视图名称
modelAndView.setViewName("itemList");
return modelAndView;
}