SpringMVC学习笔记——视频补充3

高级参数绑定

数组类型的参数绑定

使用场景:页面中多个商品信息,多选后批量删除;
**实现:**jsp页面定义input复选框;Vo类定义数组作为成员变量;controller中以Vo作为形式参数;
jsp:

<!-- value,表示这个控件的值; -->
<!-- name属性名称要等于vo中接收的属性名; -->
<td><input type="checkbox" name="ids" value="${item.id} "/></td>

Vo类:

public class QueryVo {
    //...
    private Integer[] ids;
    //...
}

Controller:

@RequestMapping("/delAll")
public String delAll(QueryVo vo) throws Exception{
    //如果批量删除一堆input复选框,那么可以提交数组;(只有input复选框被选中时,才能提交)
    return "";
}

List类型的绑定

业务场景:批量修改;
看下面程序的注释!
实现:

<c:forEach items="${itemList }" var="item" varStatus="status">
<tr>
    <!-- 总结:如果批量删除,可以用List<pojo>来接收,页面上input框的name属性值=vo中接收的集合属性名称+[list的下标]+.+list泛型的属性名称; -->
    <!-- 传list时:name属性也是等于vo中接收的属性名.属性名 -->
    <!-- 解释:就是itemsList是个成员对象,包含若干属性:id,name等; -->
    <!-- 这里为了将数据正确的放到list的正确位置,所以需要指定到属性名这一层 -->
    <td>
        <input type="checkbox" name="ids" value="${item.id} "/>
        <!-- 这里要循环存入,所以要获取到每次要存入list的哪一个;所以要借助foreach的循环次数的计数,获得次序; -->
        <input type="hidder" name="itemsList[${status.index}].id" value="${item.id}"/>
    </td>
    <td><input type="hidder" name="itemsList[${status.index}]." value="${item.name }"/></td>
    <td><input type="hidder" name="itemsList[${status.index}]." value="${item.price }"/></td>
    <td><input type="hidder" name="itemsList[${status.index}]." 
               value="<fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/>"/></td>
    <td><input type="hidder" name="itemsList[${status.index}]." value="${item.detail }"/></td>

    <td><a href="${pageContext.request.contextPath }/itemEdit.action?id=${item.id}">修改</a></td>

</tr>
</c:forEach>

@RequestParam

作用:使用简单数据类型进行参数绑定时,原本是要求参数的名称要跟jsp页面中name属性一致;通过@RequestParam,可实现
要求:@RequestParam后面的要跟jsp页面中name属性一致;之后的形参名称可以随便写;
实现:

public String update(@RequestParam("id") Integer idddd,String name, Float price, String detail) throws Exception{

}

@RequestMapping注解的使用

作用:标记url到请求方法的映射
可以在类上加@RequestMapping,作用是给url个目录,防止在项目中出现请求方法重名;
一种使用:

@Controller
//窄化请求映射:为防止你和队友在controller方法起名的时候重名,所以相当于在url中加了一层目录,防止重名;
@RequestMapping("/items")
public class ItemsController {
    //...
}

另一种使用
作用: 限制请求的方式(请求方式,比如说get,post等);
又,Http Status405,表示找不到方法;
又,一般不这样使用;
实现:

    @RequestMapping(value="/list",method=RequestMethod.GET)
    public ModelAndView itemsList() throws Exception{
        List<Items> list=itemsService.list();
        ModelAndView modelAndView =new ModelAndView();
        //设置value:
        modelAndView.addObject("itemList",list);
        //设置view:
        modelAndView.setViewName("itemList");
        return modelAndView;
    }

Note:
为啥RequestMapping的url中要加个/:因为一旦如果忘记在方法上加/,仅有类的url,就会造成访问错误;(解释不太清楚=。=)

Controller方法返回值

controller方法返回值

返回值:指定返回到哪个页面, 指定返回到页面的数据
1)ModelAndView

  • modelAndView.addObject(“itemList”, list); 指定返回页面的数据
  • modelAndView.setViewName(“itemList”); 指定返回的页面

2)String**(推荐使用)**

  • 返回普通字符串,就是页面去掉扩展名的名称, 返回给页面数据通过Model来完成:
    model.addAttribute(“item”, item);
  • 返回的字符串以forward:开头为请求转发
  • 返回的字符串以redirect:开头为重定向

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

  • 可以使用request.setAttribute 来给页面返回数据:requests.setAttribute(“arg”,arg);
  • 可以使用request.getRquestDispatcher(“页面名称”).forward(request,response)来指定返回的页面;这里要注意,页面名称的写法:因为不走springmvc组件(不能使用springmvc配置文件中的视图解析器的配置),所以这里要写完整的jsp路径名称,如:/WEB-INF/jsp/success.jsp;
  • 如果controller返回值为void则不走springMvc的组件,所以要写页面的完整路径名称

controller中调用controller中的其他方法

请求转发实现:

@RequestMapping("/updateitem")
public String update(Items items,Model model) throws Exception{
    itemsService.updateItems(items);
    //如果想实现更新完数据后,跳转到编辑页,则需要方法间进行调用;
    //实现的两种方式:
    //重定向:浏览器中url发生改变,request域中的数据不可以带到重定向后的方法中;
    //请求转发:浏览器中url不发生改变,request域中的数据可以带到转发后的方法中;
    //问题:这里是给model赋值,editItem中获取的不是request域中的数据么?
    //因为model,底层用的是request域;呵呵;
    model.addAttribute("id",items.getId());
    //springmvc中请求转发:返回的字符串以forward:开头的都是请求转发;
    //后面的forward:itemEdit.action表示相对路径,相对路径就是相对于当前目录。
    //当前为类上面指定的items目录。
    //在当前目录下可以使用相对路径随意跳转到某个方法中;
    //后面forward:/itemEdit.action路径中以斜杠开头的为绝对路径,绝对路径从项目名后面开始算;
    return "forward:itemEdit.action";
    //return "forwar:/items/itemEdit.action";
}

重定向实现:

    @RequestMapping("/updateitem")
    public String update(Items items,Model model,HttpServletRequest request) throws Exception{
        itemsService.updateItems(items);
        //如果想实现更新完数据后,跳转到编辑页,则需要方法间进行调用;
        //实现的两种方式:
        //重定向:浏览器中url发生改变,request域中的数据不可以带到重定向后的方法中;
        //在springmvc中凡是以redirect:字符串开头的都为重定向
        model.addAttribute("id",items.getId());
        //如果用request:没办法把id带过去;edit中会报异常;
        request.setAttribute("id", items.getId());
        return "redirect:itemEdit.action";
    }

总结
1. 相对路径:相对于当前目录,也就是在当前类的目录下,这时候可以使用相对路径跳转
2. 绝对路径:从项目名后开始.
3. 在springMvc中不管是forward还是redirect后面凡是以/开头的为绝对路径,不以/开头的为相对路径;例如:forward:/items/itemEdit.action 为绝对路径;forward:itemEdit.action为相对路径

Springmvc中异常处理

哈哈哈哈哈哈:(今日份的大笑)
异常是什么:平时写的bug就是异常;(笑点在于,写的不是代码,是bug=。=)
运行时异常:bug;
哇靠,这段视频不完整=。= 嘤哈哈嘤哈哈哈哈哈哈;

图片上传处理

作用:为了上传图片,哈哈哈哈哈;
企业开发中,上传图片会将图片传到图片服务器上;而不是放到当前应用服务器上=。=
这里练习,创建使用虚拟的图片服务器。

创建图片服务器

步骤:
tomcat服务器双击,打开module界面;Add External Web Module;
Path:相当于访问图片的项目名;
Document Base:放图片的文件夹
最后ctrl+S保存;
测试:通过localhost:8080/项目名/图片名,可以访问到图片,说明创建完成。

上传图片的实现

jsp中一些修改:
上传图片时,要增加form标签的属性:enctype=”multipart/form-data”;
因为图片要以二进制流的方式传输,这里的设置就是以二进制流的方式传输;
jsp:

    <!-- 上传图片是需要指定属性 enctype="multipart/form-data" -->
    <!-- <form id="itemForm" action="" method="post" enctype="multipart/form-data"> -->

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

导入fileupload的jar包:上传的图片是流的形式,所以需要upload来进行解析;
springmvc.xml:

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

Controller方法中:
1. 获取图片完整名称;
2. 使用随机生成的字符串+源图片扩展名,组成新的图片名称,防止图片重名;
3. 将图片保存到硬盘;
4. 将图片名称保存到数据库;

    @RequestMapping("/updateitem")
    public String update(MultipartFile pictureFile,Items items,Model model,HttpServletRequest request) throws Exception{
        //pictureFile是图片;
        //1. 获取图片完整名称;(获取的是type="file"的input框中的name属性的值;)
        String fileStr=pictureFile.getOriginalFilename();
        //2. 使用随机生成的字符串+源图片扩展名,组成新的图片名称,防止图片重名; 
        String newfileName=UUID.randomUUID().toString()+fileStr.substring(fileStr.lastIndexOf("."));
        //3. 将图片保存到硬盘;
        pictureFile.transferTo(new File("D:\\LeeDownload\\ssmpicture\\"+newfileName));
        //4. 将图片名称保存到数据库;
        items.setPic(newfileName);
        itemsService.updateItems(items);
        //...
    }

讲真,没有特别明白=。=;以后用到再看吧=。=

Json数据交互

json:常用手机服务端;一种数据压缩格式,提高网络数据传输效率和降低传输成本;(em)
**目标:**controller获取页面传来的json字符串;处理后,将数据以json的格式传回给页面。
步骤:

  • 导入相关jar包;
  • springmvc.xml配置:注意,如果配置了注解驱动,则不需要再配置json相关内容;

  • Note:将js啊图片啊什么的,都放到WebContent目录下;而jsp要放到WEB-INF下,为了安全;()
    实现:
    jsp:
<script type="text/javascript">
    function sendJson(){
        //使用ajax,请求完之后,会自动返回到当前页;
        $.ajax({
            //post请求;
            type:"post",
            //要提交到的controller:
            url:"${pageContext.request.contextPath }/items/sendJson.action",
            //contentType,请求体的类型;默认的是application/text,json解析不了,认为是字符串,而不是json;
            contentType:"application/json;charset=utf-8",
            //传递的数据;
            //这里要求,key要等于controller中接收的pojo对象的属性名;
            data:'{"name":"测试商品","price":99.9}',
            //对请求回来的数据的回调函数;
            success:function(data){
                alert(data);
            }
        });
    }
</script>
<input type="button" value="senJson" onClick="sendJson()"/>

controller:

    //导入jackson的jar包,在controller的方法中可以使用@RequestBody,让springMvc将json格式字符串自动转换成java中的pojo;
    //页面json的key要等于java中的pojo的属性名称;
    @RequestMapping("/sendJson")
    public String json(@RequestBody Items items) throws Exception{
        //参数是,Items对象;使用@RequestBody,springmvc可自动将json转化为Items对象,
    }

如果要返回给页面json:

    //controller方法返回pojo类型的对象并且用@ResponseBody注解,springmvc会自动将pojo对象转化成json格式字符串;
    @RequestMapping("/sendJson")
    @ResponseBody
    public String json(@RequestBody Items items) throws Exception{

    }

Springmvc实现Restful

Restful:url的命名风格
资源操作:及各种请求;
post请求:提交表单:更新、修改数据;
get请求:此外的其他请求;
资源定位:互联网上的所有东西,页面,图片等。要求url中没有动词,只有名词,没有参数(不能有?传参)(也不会以action结尾之类的);
(另,用汉语拼音的缩写是很扯的一种行为)
使用注解的缺点:如果不使用统一的命名方式,可维护性不高;
首先设置url-pattern:

  <servlet-mapping>
    <servlet-name>springMvc</servlet-name>
    <!-- 三种url拦截方式:
    *.action    代表拦截后缀名为.action结尾的;
    /           拦截所有,但是不包括.jsp
    /*          拦截所有,包括.jsp
     -->
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>

修改之前的itemEdit.jsp:

<!-- 这里是两个参数的情况。且这里的顺序要与controller方法中一致; -->
        <td><a href="${pageContext.request.contextPath }/items/itemEdit/${item.id}/张">修改</a></td>

修改controller接收方法:

    //通过@PathVariable可以接受url中传入的参数;
    //要求:requestMapping后的参数名,PathVariable后的参数名,与jsp页面中的参数名要相同;
    //@RequestMapping("/itemEdit/{id}/{name}")中接收参数使用大括号中加上变量名称
    //@PathVariable中的变量名称要和RequestMapping中的变量名称相同;
    @RequestMapping("/itemEdit/{id}/{name}")
    public String itemEdit(@PathVariable("id") Integer id,@PathVariable("name") String name){

    }

又在controller方法中重定向或者请求转发方式到别的方法时,也要删去.action;需要传递的数据通过以下方式传递:(通过url传,而不是通过request域传;)

return "forward"itemEdit/"+items.getId();
//之前方法:
return "forward:itemEdit.action";

拦截器

作用:拦截请求;权限验证时常用;

实现

步骤:
1)新建类,继承HandlerInterceptor类;
2)在springmvc中配置:

    <!-- 配置拦截器 -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 拦截请求的路径;要拦截所有,必须配置成/** -->
            <!-- 意思就是:对于什么,进行拦截; -->
            <mvc:mapping paht="/**"></mvc:mapping>
            <!-- 指定拦截器的位置 -->
            <bean class="cn.itheima.interceptor.Interceptor1"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

HandlerIntercepter类的写法及其中方法的使用:

public class Interceptor1 implements HandlerInterceptor {

    //执行时机:Controller已经执行,ModelAndView已经返回;(即controller方法后)
    //使用场景:记录操作日志,比如记录登陆用户的ip,时间等信息;
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("========Interceptor1====afterCompletion=======");
    }

    //执行时机:controller方法已经执行,ModelAndView没有返回;(即controller方法中)
    //使用场景:可以在此方法中设置全局的数据处理业务;
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        // TODO Auto-generated method stub
        System.out.println("========Interceptor1====postHandle=======");
    }

    //返回布尔值:如果返回true放行,返回false拦截;
    //这里要放行后才可能执行post和after方法;
    //执行时机:controller方法没有被执行,ModelAndView没有被返回;(即controller方法前,还未进入controller方法)
    //使用场景:权限验证(登录时,拦截请求,验证用户名密码;将登陆信息放入session中;之后所有的请求,验证session是否有 登录信息,若无,则拦截;若有,则放行;)
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        // TODO Auto-generated method stub      
        System.out.println("========Interceptor1====preHandle=======");
        return true;
    }
}

多个拦截器

执行顺序:pre方法的执行顺序与在springmvc配置文件中的配置顺序一致;

拦截器应用(登录权限验证)

简单来说:
当通过url申请访问页面时,如果设置了拦截器,就会首先根据其设置的拦截限制(拦截谁)(在配置文件中设置),判断是否拦截;如果需要拦截,首先执行pre方法,该方法如果返回true,则放行;放行的含义是,继续根据url,找到对应的controller。拦截器中最常用的也是pre方法。
步骤:
1. 编写登录的controller,编写跳转到登录页面的方法,编写登录验证方法;
2. 编写登录页面;
3. 编写拦截器(最后记得要在springmvc.xml配置文件中注册该拦截器)。

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

实现:
controller:

@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";
    }
}

登录页面:

<form action="${pageContext.request.contextPath }/login/submit" method="">
<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>

拦截器:

    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;
    }

总结

  1. 参数绑定
    一共有七种:默认支持的类型:Request,Response,Session,Model;基本数据类型和String;pojo类;pojo的包装类;Converter自定义转换器;数组;List;
  2. controller方法返回值
    详见视频补充2
  3. 架构级别异常处理
    主要为了防止项目上线后给用户抛500等异常信息,所以需要在架构级别上整体处理.hold住异常;
    首先自定义全局异常处理器实现HandlerExceptionResolver接口;
    在spirngMvc.xml中配置生效。
  4. 上传图片
    1)在tomcat中配置虚拟图片服务器;
    2)导入fileupload的jar包
    3)在springMvc.xml中配置上传组件
    4)在页面上编写上传域,更改form标签的类型
    5)在controller方法中可以使用MultiPartFile接口接收上传的图片
    6)将文件名保存到数据库,将图片保存到磁盘中
  5. json数据交互
    需要加入jackson的jar包;
    @Requestbody:将页面传到controller中的json格式字符串自动转换成java的pojo对象;
    @ResponseBody:将java中pojo对象自动转换成json格式字符串返回给页面。
  6. RestFul支持
    就是对url的命名标准,要求url中只有能名词,没有动词(不严格要求),但是要求url中不能用问号?传参;
    传参数:
    页面:$ {pageContext.request.contextPath }/items/itemEdit/${item.id}
    方法: @RquestMapping(“/itemEdit/{id}”)
    方法: @PathVariable(“id”) Integer idd
  7. 拦截器
    作用:拦截请求,一般做登录权限验证时用的比较多;
    1)需要编写自定义拦截器类,实现HandlerInterceptor接口
    2)在spirngMvc.xml中配置拦截器生效
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值