SpringMVC常见应用
1、@RequestMapping
此注解放在类上用于窄化请求、防止重名
@Controller
@RequestMapping("item")
public class ItemsController {
@Autowired
private ItemsService itemsService;
@RequestMapping(value="/list",method=RequestMethod.POST)
public ModelAndView itemsList() {
List<Items> items = itemsService.getItems();
ModelAndView modelAndView = new ModelAndView();
modelAndView.addObject("itemlist", items);
modelAndView.setViewName("itemList");
return modelAndView;
}
Controller返回值
a、ModelAndView(对request的封装和扩展)
两个重要的方法:addObject(obj,obj)-指定返回页面的数据,也是使用的request.setAttribute()方法。setViewName()指定返回的页面。
b、String(推荐使用)
返回普通的字符串-就是页面去掉扩展名的名称,数据通过model填写。
返回的字符串以forward:开头表示请求转发
返回的字符串以redirect:开头表示重定向
c、返回void(破坏了SpringMVC的结构不建议使用)
使用setAttribute设置返回页面的数据,使用sendRedirect和getRequestDispatcher("页面的路径").forward(req,rep)方式指定返回页面。
在这种方式下,Controller不走SpringMVC组件,那么需要指定页面完整的路径/WEB-INF/jsp/**
相对路径:相对于当前目录,也就是当前类的目录下,这个时候可以使用相对路径跳转
绝对路径:从项目名开始
在SpringMvc中不论forward和redirect,都是以"/"开头的为绝对路径,不以"/"开头的是相对路径。forward:/items/list.action为绝对路径,redirect:list.action是相对路径。
3、上传文件
a、配置虚拟目录
在tomcat安装目录下conf/server.xml中添加:
<Context docBase="/home/lxj/temp" path="/pic" reloadable="false"/>
访问http://localhost:8080/pic/xx.jpg,即可访问/home/lxj/temp下的图片。
在eclipse下创建:
如果设置成功,那么可以在浏览器中访问文件:
enctype="multipart/form-data"
<form id="itemForm" action="${pageContext.request.contextPath }/updateitem.action" enctype="multipart/form-data" method="post">
其中enctype="multipart/form-data"在上传文件的时候必须加上
c、配置文件上传组件
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<!-- 设置上传文件的最大尺寸为5MB -->
<property name="maxUploadSize">
<value>5242880</value>
</property>
</bean>
Controller:
public String updateItem(MultipartFile pictureFile, Items items) {
try {
// 1、获取文件名
String fileStr = pictureFile.getOriginalFilename();
// 2、生成新的文件名,防止重名
String newFileName = UUID.randomUUID().toString()+fileStr.substring(fileStr.lastIndexOf("."));
pictureFile.transferTo(new File("/home/lxj/temp/"+newFileName));
items.setPic(newFileName);
itemsService.updateItems(items);
return "success";
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "error";
}
}
扩展:如果是多个文件上传,那么将input的name属性变为一致,将Controller中的MultipartFile变为数组接收,亦可以直接使用common-fileupload组件直接接收form表单数据,他会将每个Input变为一个域,然后迭代判断是否为文件,进行操作。
4、json数据交互
@ResponseBody注解读取http的内容(字符串),通过SpringMVC提供的HttpMessageConverter接口,将读到的内容转化成json、xml等格式的数据并绑定Controller方法的参数上。
@RequestBody SpringMVC自动的将json转换成Java中的pojo,前提是json中的key必须和pojo的属性名一致。
测试:导入Jquery
<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
function sendJson(){
$.ajax({
type:"post",
url:"${pageContext.request.contextPath }/sendJson.action",
contentType:"application/json;charset=utf-8",
data:'{"name":"测试商品","price":99.9}',
success:function(data){
alert(data);
}
});
}
</script>
<input type="button" value="json" οnclick="sendJson()"/>
Controller:
//@RequestBody SpringMVC自动的将json转换成Java中pojo,
// json中的key必须和pojo的属性名一致
// @ResponseBody自动的将pojo转换成json格式
@RequestMapping("sendJson")
@ResponseBody
public Items sendJson(@RequestBody Items items) {
System.out.println(items);
return items;
}
5、restful风格
通俗的将知识一种规范和人为约定的资源定位和资源操作风格,要求url中只能有名词,不能有动词。
修改servlet-mapping的映射路径
<!-- *.action 拦截后缀名action结尾的
/拦截所有,不包括jsp
/*拦截所有包括jsp
-->
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
修改url
<td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>
变为:
<td><a href="${pageContext.request.contextPath }/items/itemEdit/${item.id}/${item.name}">修改</a></td>
Controller:接收参数已经映射的写法
/**
* springmvc中默认支持的类型,可以加也可以不加
* @param req
* @param rep
* @param model
* @param session
* @PathVariable获取url中传过来的参数,域页面/itemEdit/{id}/{name}和方法中的形参名必须和url的一致
* @return
*/
@RequestMapping("/itemEdit/{id}/{name}")
public String itemEdit(@PathVariable("id") Integer id,@PathVariable("name") String name ,HttpServletRequest req,HttpServletResponse rep,Model model) {
Items items=itemsService.findItemsById(id);
// Model其实就是使用request传递参数,只是对request进行了扩展
model.addAttribute("item", items);
// 如果返回的是一个简单的字符串,SpringMvc就会认为这是一个页面
return "editItem";
}
如果是使用了redirect重定向的情况下:
/ 接受pojo类型、要求页面个的属性名称必须和接受参数的pojo类型参数属性名一致
@RequestMapping("/updateitem")
// public String updateItem(Integer id ,String name ,Float price,String detail) {
public String updateItem(MultipartFile pictureFile, Items items,Model model) {
try {
// 1、获取文件名
String fileStr = pictureFile.getOriginalFilename();
// 2、生成新的文件名,防止重名
String newFileName = UUID.randomUUID().toString()+fileStr.substring(fileStr.lastIndexOf("."));
pictureFile.transferTo(new File("/home/lxj/temp/"+newFileName));
items.setPic(newFileName);
itemsService.updateItems(items);
model.addAttribute("id", items.getId());
// redirect:重定向,forward:请求转发
return "redirect:itemEdit";
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "error";
}
浏览器:
出现404错误,并且http://localhost:8080/day19-ssm/items/itemEdit?id=1,仍然是以问号传参数的
改变:
// 接受pojo类型、要求页面个的属性名称必须和接受参数的pojo类型参数属性名一致
@RequestMapping("/updateitem")
// public String updateItem(Integer id ,String name ,Float price,String detail) {
public String updateItem(HttpServletRequest request,HttpServletResponse response,MultipartFile pictureFile, Items items,Model model) {
try {
// 1、获取文件名
String fileStr = pictureFile.getOriginalFilename();
// 2、生成新的文件名,防止重名
String newFileName = UUID.randomUUID().toString()+fileStr.substring(fileStr.lastIndexOf("."));
pictureFile.transferTo(new File("/home/lxj/temp/"+newFileName));
items.setPic(newFileName);
itemsService.updateItems(items);
// model.addAttribute("id", items.getId());
// redirect:重定向,forward:请求转发
// String name = new String(items.getName().getBytes("iso8859-1"), "utf-8");
String starName = items.getName();
response.setHeader("Content-type", "text/html;charset=UTF-8");
String name =
java.net.URLEncoder.encode(starName,"UTF-8");
return "redirect:itemEdit"+"/"+items.getId()+"/"+name;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return "error";
}
注意:之所以要进行URL编码,是因为在浏览器中中文乱码了,设置响应头告诉浏览器解析方式没有,tomcat中get解析编码集设置没用,所以只能是想到进行查看响应消息中的restful风格下的编码,发现中文给编码了,所以想到这里也需要人为的进行编码。
6、SpringMVC拦截器
org.springframework.web.servlet.HandlerInterceptor
public class interceptor1 implements HandlerInterceptor {
// Controller已经执行,ModelAndView已经返回,
// 记录操作日志、记录IP等
@Override
public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
throws Exception {
System.out.println("========="+"interceptor1"+"afterCompletion=====");
}
// Controller已经执行,ModelAndView没有返回
// 处理全局需要的信息
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
throws Exception {
System.out.println("========="+"interceptor1"+"postHandle=====");
}
// 返回布尔值,返回true放行、返回false拦截(最常用的)
// 执行时机:Controller还未执行,ModelAndView还未被返回
// 通常用于用户登录检查、权限验证
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
System.out.println("========="+"interceptor1"+"preHandle=====");
return false;
}
}
SpringMVC中配置拦截器:
<!-- 拦截器配置
多个拦截器,按照配置的顺序进行执行
-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 要拦截所有必须配置为/** -->
<mvc:mapping path="/**"/>
<bean class="cn.lier.interceptor.interceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 要拦截所有必须配置为/** -->
<mvc:mapping path="/**"/>
<bean class="cn.lier.interceptor.interceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
实例:登录验证
1、编写一个Controller、一个跳转登录页、一个登录校验方法
2、登录页面
3、编写拦截器
创建login.jsp:
<form action="${pageContext.request.contextPath }/login/submit" method="post">
<table>
<tr>
<td>用户名:<input type="text" name="name" /></td>
</tr>
<tr>
<td>密 码:<input type="password" name="pwd"/></td>
</tr>
<tr>
<td><input type="submit" name="登录"/></td>
</tr>
</table>
</form>
LoginController:
@Controller
@RequestMapping("/login")
public class LoginController {
@RequestMapping("/login")
public String login() {
return "login";
}
@RequestMapping("/submit")
public String submit(String name ,String pwd,HttpServletRequest request) {
HttpSession session = request.getSession();
// 从数据库中获取数据,匹配
if(name != null) {
session.setAttribute("name", name);
}
return "redirect:/items/list";
}
}
LoginInterceptor:
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse arg1, Object arg2) throws Exception {
// 1、判断是否为登录路径,是放行
if(req.getRequestURI().lastIndexOf("/login")>0) {
return true;
}
// 判断session中是否有登录信息,如果没有跳转到登录页面
if(req.getSession().getAttribute("name") !=null) {
return true;
}
System.out.println("========");
req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, arg1);
return false;
}
SpringMVC拦截器配置:
<!-- 拦截器配置
多个拦截器,按照配置的顺序进行执行
-->
<mvc:interceptors>
<mvc:interceptor>
<!-- 要拦截所有必须配置为/** -->
<mvc:mapping path="/**"/>
<bean class="cn.lier.interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
效果图:
输入:http://localhost:8080/day19-ssm/items/list转发到了login.jsp
输入密码提交跳转首页这里是列表页: