SpringMVC(二)

一、绑定数组和List

1、绑定数组参数

通过id数组批量删除

<form action="${pageContext.request.contextPath }/deleteAll.action" method="post">
    <table width="100%" border=1>
        <tr>
            <td>
<
input type="submit" value="批量删除"/>
       </
td> </tr> </table> <table width="100%" border=1> <c:forEach items="${itemList }" var="item" varStatus="status"> <tr> <!-- name属性名称要等于vo中的接收的id数组属性名 --> <td> <input type="checkbox" name="ids" value="${item.id }"/> </td> </tr> </c:forEach> </table> </form>
// 窄化请求映射 localhost:8081/ssm0523-1/items/deleteAll.action
@RequestMapping("/items")
public class ItemsController {

    @Autowired
    private ItemsService itmesService;

    @RequestMapping("/deleteAll")
    public String delAll(QueryVo vo) throws Exception{
        //如果批量删除,一堆input复选框,那么可以提交数组.(只有input复选框被选中的时候才能提交)
        System.out.println(vo);
        return "";    // 不跳转页面
    }
}

包装类QueryVo中有private Integer[] ids属性

2、绑定List集合

通过List<Items>集合批量修改

包装类QueryVo中有private List<Items> itemList;

<form action="${pageContext.request.contextPath }/updateAll.action" method="post">
<!-- status.index循环次数 -->
<c:forEach items="${itemList }" var="item" varStatus="status">
<table width="100%" border=1>
<tr>
    <!-- name属性名称要等于vo中的接收的属性名 -->
    <!-- 如果批量删除,可以用List<pojo>来接收,页面上input框的name属性值= vo中接收的集合属性名称+[list的下标]+.+list泛型的属性名称 -->
    <td>
        <input type="checkbox" name="ids" value="${item.id }"/>
        <!-- 隐藏域,不显示,但是提交 -->
        <input type="hidden" name="itemsList[${status.index }].id" value="${item.id }"/>
    </td>
    <td><input type="text" name="itemsList[${status.index }].name" value="${item.name }"/></td>
    <td><input type="text" name="itemsList[${status.index }].price" value="${item.price }"/></td>
    <td><input type="text" name="itemsList[${status.index }].createtime" 
               value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
    <td><input type="text" name="itemsList[${status.index }].detail" value="${item.detail }"/></td>
    
    <td><a href="${pageContext.request.contextPath }/items/itemEdit/${item.id}">修改</a></td>

</tr>
</table>
</c:forEach>
</form>
@RequestMapping("/updateAll")
public String updateAll(QueryVo vo) throws Exception{
    System.out.println(vo);
    return "";
}

二、@RequestMapping注解

定义不同的处理器映射规则

1、请求URL路径映射(加在方法上)

@RequestMapping(value="/item")或@RequestMapping("/item)

value的值是数组,可以将多个url映射到同一个方法,只有一个值时可以不写value

2、窄化请求路径(加在类上)

@RequestMapping(value="/item")

请求的URL前缀,类下所有的所有的方法都要加上此前缀,/item/itemList

3、限定请求方法

@RequestMapping(method = RequestMethod.GET)    限定GET方式

用POST报错405

三、Controller方法返回值

指定返回到的页面和返回到页面的数据

1、ModelAndView

modelAndView.addObject("itemList", list); 指定返回页面的数据

modelAndView.setViewName("itemList");  指定返回的页面

2、String(推荐使用)

返回普通字符串,就是页面去掉扩展名的名称, 返回给页面数据通过Model来完成

返回的字符串以forward:开头为请求转发

返回的字符串以redirect:开头为重定向

3、返回void(使用它破坏了springMvc的结构,所以不建议使用)

可以使用request.setAttribut 来给页面返回数据

可以使用request.getRquestDispatcher().forward()来指定返回的页面

如果controller返回值为void则不走springMvc的组件,所以要写页面的完整路径名称(/WEB-INF/)

相对路径:相对于当前目录,也就是在当前类的目录下,这时候可以使用相对路径跳转

绝对路径:从项目名后开始

在springMvc中不管是forward还是redirect后面凡是以/开头的为绝对路径,不以/开头的为相对路径

forward:/items/itemEdit.action 为绝对路径

forward:itemEdit.action为相对路径

四、异常处理(架构级别)

主要为了防止项目上线后给用户抛500等异常信息,所以需要在架构级别上整体处理.hold住异常
首先自定义全局异常处理器实现HandlerExceptionResolver接口
在spirngMvc.xml中配置生效

五、上传图片

1、配置虚拟目录

在tomcat上配置图片虚拟目录,在tomcat下conf/server.xml中添加:

<Context docBase="F:developupload	emp" path="/pic" reloadable="false"/>

访问http://localhost:8080/pic即可访问F:developupload emp下的图片

也可以通过eclipse配置

2、导包

CommonsMultipartResolver依赖commons-fileupload-1.2.2.jar、commons-io-2.4.jar

3、配置解析器

springmvc.xml中

<!--文件上传 -->
    <bean id="multipartResolver"
    class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置上传文件的最大尺寸为5MB -->
        <property name="maxUploadSize">
            <value>5242880</value>
        </property>
    </bean>

4、图片上传

@RequestMapping("/updateitem")
public String update(MultipartFile pictureFile,Items items, Model model, HttpServletRequest request) throws Exception{
    //1. 获取图片完整名称
    String fileStr = pictureFile.getOriginalFilename();
    //2. 使用随机生成的字符串+源图片扩展名组成新的图片名称,防止图片重名
    String newfileName = UUID.randomUUID().toString() + fileStr.substring(fileStr.lastIndexOf("."));
     //3. 将图片保存到硬盘
    File uploadPic = new java.io.File("F:/develop/upload/temp/"+newFileName);
    if(!uploadPic.exists()){
    uploadPic.mkdirs();
    }
    pictureFile.transferTo(uploadPic);
    //4.将图片名称保存到数据库
    items.setPic(newfileName);
    itmesService.updateItems(items);

    return "itemEdit"
}

5、JSP页面

form添加enctype="multipart/form-data"

<form id="itemForm" action="${pageContext.request.contextPath }/item/editItemSubmit.action"
        method="post"enctype="multipart/form-data">
     <input type="hidden" name="pic" value="${item.pic }"/>
</form>

file的name与controller形参一致

<tr>
    <td>商品图片</td>
    <td><c:if test="${item.pic !=null}">
        <imgsrc="/pic/${item.pic}" width=100 height=100 />
        <br/>
        </c:if><input type="file" name="pictureFile" /></td>
</tr>

六 JSON数据交互

 @RequestBody

将页面传到Controller中的JSON格式字符串自动转换成java的POJO对象,并绑定到Controller方法的参数上

@ResponseBody

将Java中POJO对象自动转换成JSON格式字符串返回给页面,通过response响应给客户端

@Controller
@RequestMapping("/items")
public class ItemsController {

    @Autowired
    private ItemsService itmesService;

    //导入jackson的jar包在 controller的方法中可以使用@RequestBody,让spirngMvc将json格式字符串自动转换成java中的pojo
    //页面json的key要等于java中pojo的属性名称
    //controller方法返回pojo类型的对象并且用@ResponseBody注解,springMvc会自动将pojo对象转换成json格式字符串
    @RequestMapping("/sendJson")
    @ResponseBody
    public Items json(@RequestBody Items items) throws Exception{
        System.out.println(items);
        return items;
        }
}

七、Restful开发

资源定位及资源操作的风格,不是标志,也不是协议,对HTTP协议的诠释

就是对URL的命名标准,要求url中只有能名词,没有动词(不严格要求),但是要求url中不能用问号?传参
传参数:
  页面:${pageContext.request.contextPath }/items/itemEdit/${item.id}
  Controller方法中接收: @RquestMapping("/itemEdit/{id}")
  方法: @PathVariable("id") Integer idd

/**
*通过@PathVariable可以接收url中传入的参数 *@RequestMapping("/itemEdit/{id}")中接收参数使用大括号中加上变量名称, @PathVariable中的变量名称要和RequestMapping中的变量名称相同 */ @RequestMapping("/itemEdit/{id}") 请求的URL public String itemEdit(@PathVariable("id") Integer id, HttpServletRequest reuqest, Model model) throws Exception{ @PathVariable获得URL的数据
}
${pageContext.request.contextPath }/items/itemEdit/${item.id}

八、拦截器

类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理,一般做登录权限验证时用的比较多

1、需要编写自定义拦截器类,实现HandlerInterceptor接口

2、在spirngMvc.xml中配置拦截器生效

实现HandlerInterceptor接口

public class Interceptor implements HandlerInterceptor{
    /**
     * controller执行前调用此方法,ModelAndView没有被返回
     * 返回true表示继续执行,返回false中止执行
     * 这里可以加入登录校验、权限拦截等
     */
    public boolean preHandle(HttpServletRequest request, 
        HttpServletResponse response, Object handler) throws Exception {
    }
    
    /**
     * controller执行后但未返回视图ModelAndView前调用此方法
     * 这里可在返回用户前对模型数据进行加工处理,比如这里加入公用信息以便页面显示
     */
    public void postHandle(HttpServletRequest request, 
        HttpServletResponse response, Object handler, 
        ModelAndViewmodelAndView) throws Exception {
 }
  /**
     * controller执行后且视图ModelAndView返回后调用此方法
     * 这里可得到执行controller时的异常信息
     * 这里可记录操作日志,资源清理等
     */
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    }
}

springmvc.xml中配置拦截器

<mvc:interceptors>
        <!-- 可配置多个拦截器,顺序执行 -->
    <mvc:interceptor>
        <!-- 拦截请求的路径    要拦截所有必需配置成/** -->
        <mvc:mapping path="/**"/>
        <!-- 指定拦截器的位置 -->
        <bean class="cn.guojie.interceptor.LoginInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>

九、登录权限验证

1、编写登录的controller, 编写跳转到登录页面的方法,  编写登录验证方法

2、编写登录页面

3、编写拦截器

运行过程:
(1)访问随意一个页面,拦截器会拦截请求,会验证session中是否有登录信息
        如果已登录,放行
        如果未登录,跳转到登录页面
(2)在登录页面中输入用户名,密码,点击登录按钮,拦截器会拦截请求,如果是登录路径放行
        在controller方法中判断用户名密码是否正确,如果正确则将登录信息放入session

@Controller
@RequestMapping("/login")
public class LoginController {

    //跳转到登录页面
    @RequestMapping("/login")
    public String login() throws Exception{
        return "login";
    }
    
    @RequestMapping("/submit")
    public String submit(String username, String pwd ,HttpServletRequest request) throws Exception{
        
        HttpSession session = request.getSession();
        //判断用户名密码的正确性,如果正确则将登录信息放入session中
        //这里简写,真正项目中需要去数据库中校验用户名和密码
        if(username != null){
            session.setAttribute("username", username);
        }
        
        //跳转到列表页显示 重定向
        return "redirect:/items/list";
    }
}
public class LoginInterceptor implements HandlerInterceptor {

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object arg2) throws Exception {
        //判断当前访问路径是否为登录的路径,如果是则放行
        if(request.getRequestURI().indexOf("/login") > 0){
            return true;
        }
        
        //判断session中是否有登录信息,如果没有则跳转到登录页面,如果有则放行
        HttpSession session = request.getSession();
        if(session.getAttribute("username") != null){
            return true;
        }
        
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
        return false;
    }

}

springmvc.xml中配置拦截器

<mvc:interceptors>
    <mvc:interceptor>
        <!-- 拦截请求的路径    要拦截所有必需配置成/** -->
        <mvc:mapping path="/**"/>
        <!-- 指定拦截器的位置 -->
        <bean class="cn.guojie.interceptor.LoginInterceptor"></bean>
    </mvc:interceptor>
</mvc:interceptors>
<form action="${pageContext.request.contextPath }/login/submit" method="post">
<table>
    <tr><td>用户名:<input name="username" type="text"/></td></tr>
    <tr><td>密码:<input name="pwd" type="password"/></td></tr>
    <tr><td><input value="登录" type="submit"/></td></tr>
</table>
</form>

只要有请求就会被先被拦截器拦截

请求,地址栏访问 ----> 要直接是/login/login地址访问就拦截放行跳到login.jsp,要地址不是 ----> 拦截器拦截判断登录路径和登录信息,都不满足,转发到登录页面login.jsp去登录 --->login.jsp页面submit提交时重定向再次发请求,被拦截器拦截判断登录路径,满足放行 ----> ${pageContext.request.contextPath }/login/submit请求到LoginController的submit方法中提交 ----> 重定向到商品列表页,发送请求再次被拦截器拦截,登录路径不满足,但登录信息有,放行

web.xml中

*.action:所有action后缀都拦截

/:拦截除JSP外所有,可以不写action

/*:拦截所有

有志者,事竟成,破釜沉舟,百二秦关终属楚;苦心人,天不负,卧薪尝胆,三千越甲可吞吴。
原文地址:https://www.cnblogs.com/1989guojie/p/7704385.html