springmvc基础知识记录3

1.springmvc框架基础回顾

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

2.包装类型pojo参数绑定

2.1实现方法

在这里插入图片描述

2.2页面参数和controller方法形参定义

在这里插入图片描述

3.集合类型绑定

3.1数组绑定

<input type="button" value="批量删除" onclick="deleteItems()"/>
function deleteItems() {
document.itemsForm.action="${pageContext.request.contextPath }/items/deleteItems.action";
document.itemsForm.submit();
}
<td><input type="checkbox" value="${item.id}" name="items_id"/></td>

上面的name的值需要和控制器的参数名一样才行

@RequestMapping("/deleteItems")
public String deleteItems(Integer[] items_id) throws Exception{
    for(int i=0;i<items_id.length;i++){
        itemsService.deleteById(items_id[i]);
    }
return "success";
}

3.2list绑定

使用List接收页面提交的批量数据,通过包装pojo接收,在包装pojo中定义list属性。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.3map绑定

在这里插入图片描述

4.服务端校验

4.1校验理解

在这里插入图片描述

4.2springmvc校验

springmvc使用hibernate的校验框架validation(和hibernate没雨关系)

校验思路:

​ 页面提交请求的参数,请求到controller方法中,使用validation进行校验,如果校验出错,将错误信息展示到页面。

具体需求:

商品修改,添加校验(校验商品名称长度,生产日期的非空校验),如果校验出错,在商品修改页面显示错误信息。

4.3环境准备

在这里插入图片描述

4.4配置校验器

<bean id="validator"    class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
    <!-- 如果不指定则默认使用classpath下的ValidationMessages.properties -->
    <property name="validationMessageSource" ref="messageSource" />
</bean>
<!-- 校验错误信息配置文件 -->
<bean id="messageSource"
      class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>CustomValidationMessages</value>
        </list>
    </property>
    <!--资源编码格式-->
    <property name="fileEncodings" value="utf-8" />
    <!--对资源文件内容缓存时间,单位秒-->
    <property name="cacheSeconds" value="120" />
</bean>

4.5校验器注入到处理器适配器中

配置方式1

<mvc:annotation-driven conversion-service="conversionService" validator="validator"></mvc:annotation-driven>

配置方式2

在这里插入图片描述

4.6在pojo中添加校验规则

在这里插入图片描述

4.7创建CustomValidationMessages.properties

#校验提示信息:items.name.length.error要写在java代码中
items.name.length.error=商品名称的长度请限制在1到30个字符
items.createtime.is.notnull=请输入商品的生产日期

4.8捕获校验错误信息

//在每个@Validated后面都需要一个BindingResult来接收对于的错误信息,是一对一配对关系的,并且顺序固定
@RequestMapping("/editItemsSubmit")
public ModelAndView editItemsSubmit(Integer id, @Validated ItemsCustom itemsCustom, BindingResult bindingResult) throws Exception{

4.9在页面显示校验错误信息

@NotNull 和 @NotEmpty 和@NotBlank 区别

@NotEmpty 用在集合类上面
@NotBlank 用在String上面
@NotNull 用在基本类型上

如果在基本类型上面用NotEmpty或者NotBlank 会出现上面的错

5.数据回显

5.1什么是数据回显

提交后,如果出现错误,将刚才提交的数据回显到刚才的提交页面

5.2pojo数据回显方法

  1. springmvc默认对pojo数据进行回显

    pojo数据传入controller方法后,springmvc自动将pojo数据放到request域,key等于pojo类型(首字母小写)

使用@ModelAttribute指定pojo回显到页面在request中的key

  1. @ModelAttribute还可以将方法的返回值传到页面

    //单独将商品类型的方法提取出来,将方法返回值填充到request域,在页面提示
    @ModelAttribute("itemsType")
    public Map<String,String> getItemsType() throws Exception{
    
        HashMap<String,String> itemsType=new HashMap<>();
        itemsType.put("001","data type");
        itemsType.put("002","clothes");
        return itemsType;
    }
    

    然后我们在itemsList.jsp页面中加入如下标签进行页面的展示:

    <td>
     <select>
      <c:forEach items="${itemsType}" var="item">
    	<option value="${item.key}">${item.value}</option>
      </c:forEach>
     </select>
    </td>
    

    成功使用@ModleAttribute注解将方法返回值返回到页面。其实这种注解的方式也是将数据填入到request域中,然后在页面中通过el表达式取出,同model.addAttribute()方法和modelAndView.addObject()方法。

6.异常处理

6.1常见异常类型

系统中异常类型有哪些?

包括预期可能发生的异常、运行时异常(RuntimeException),运行时异常不是预期会发生的。

针对预期可能发生的异常,在代码手动处理异常可以try/catch捕获,可以向上抛出。

针对运行时异常,只能通过规范代码质量、在系统测试时详细测试等排除运行时异常。

系统的dao、service、controller出现都通过throws Exception 向上抛出,最后由springmvc前端控制器交由异常处理器进行异常处理

6.2自定义异常类

在这里插入图片描述

对不同的异常类型定义异常类,继承Exception

public class CustomException extends Exception {
    //异常信息
    public String message;
    public CustomException(String message){
        super(message);
        this.message=message;
    }

    @Override
    public String getMessage() {
        return super.getMessage();
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

6.3全局异常处理器

思路:
系统遇到异常,在程序中手动抛出,dao抛给service,service给controller,controller抛给前端控制器,前端控制器调用全局异常处理器。

​ 全局异常处理器处理思路:

​ 解析出异常类型

​ 如果该 异常类型是系统 自定义的异常,直接取出异常信息,在错误页面展示

​ 如果该 异常类型不是系统 自定义的异常,构造一个自定义的异常类型(信息为“未知错误”)

springmvc提供一个HandlerExceptionResolver接口

public class CustomExceptionResolver implements HandlerExceptionResolver{

    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, javax.servlet.http.HttpServletResponse httpServletResponse, Object o, Exception ex) {
        //输出异常
        ex.printStackTrace();


        //统一异常处理代码
        //针对系统自定义的CustomException异常,就可以直接从异常中获取异常信息,将异常处理在错误页面展示
        //异常信息
        String message=null;
        CustomException customException=null;
        //如果ex是系统自定义的异常,我们就直接取出异常信息
        if (ex instanceof CustomException)
        {
            customException= (CustomException) ex;
        }else {
            customException=new CustomException("未知错误");
        }

        //错误信息
        message=customException.getMessage();
        ModelAndView modelAndView=new ModelAndView();

        modelAndView.addObject("message",message);
        modelAndView.setViewName("Name");


        return modelAndView;
    }
}

6.4 在springmvc中配置异常处理器

<!--全局异常处理器配置-->
<bean class="exception.CustomExceptionResolver"></bean>

6.5异常测试

if(itemsCustom==null){
    throw new CustomException("商品信息不存在");
}

如果与业务功能相关的异常,建议在service中抛出异常。

与业务功能没有关系的异常,建议在controller中抛出。

7. 上传图片

7.1 springmvc中对多部件类型解析

springmvc使用commons-fileupload进行图片上传。

需要导入的jar包为:commons-fileupload-1.2.2.jar和依赖包commons-io-2.4.jar。

在页面form中提交enctype=“multipart/form-data"的数据时,需要springmvc对multipart类型的数据进行解析

在springmvc.xml中配置multipart类型的解析器:

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

7.2配置虚拟目录

切记:不要把图片上传到工程目录 ,不方便进行工程维护。实际电商项目中使用专门图片服务器(http,比如apache、tomcat)。本教程使用图片虚拟目录,通过虚拟目录访问硬盘上存储的图片目录。

  1. 打开tomcat的虚拟目录

    在这里插入图片描述

  2. 点击下边的+号,选择External source

    在这里插入图片描述

  3. 选择你的虚拟目录即可

并在Application context中添加一个在服务器上访问的路径别名,我这里设置的为/pic。若想访问该目录下的图片,则在浏览器网站上输入:http://localhost:8080/pic/图片名称,(不需要写项目名称),即可在浏览器中成功访问到该图片。

**注意:**图片目录中尽量进行目录分级存储,提高访问速度(提高i/o),一般我们采用日期(年、月、日)进行分级创建

7.3编写上传图片的页面

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

7.4编写controller

if (pictureFile!=null)
{
    //图片上传成功后,将图片的地址写到数据库
    String filePath="/Users/chenzeyuan/Downloads/images";//它的值要同你设置虚拟目录时涉及的目录路径一致,
    String originalFilename=pictureFile.getOriginalFilename();

    String newFileName= UUID.randomUUID()+originalFilename.substring(originalFilename.lastIndexOf("."));

    //新文件
    File file=new File(filePath+newFileName);

    //将内存中的文件写入磁盘
    pictureFile.transferTo(file);

    //图片上传成功
    itemsCustom.setPic(newFileName);
}

8.json数据交互

8.1为什么要进行json数据交互

json数据格式是比较简单容易理解,json数据格式常用于远程接口传输,http传输json数据,非常方便页面进行提交/请求结果解析,对json数据的解析。

8.2springmvc进行json交互

@RequestBody:将请求的json数据转成java对象。
@ResponseBody:将java对象转成json数据输出。

在这里插入图片描述

  1. 请求json、输出json,要求请求的是json串,所以在前端页面中需要将请求的内容转成json,不太方便。
  2. 请求key/value、输出json。此方法比较常用。

8.3springmvc解析json需要加入的json解析包

Springmvc默认用MappingJacksonHttpMessageConverter对json数据进行转换,需要加入jackson的包:jackson-annotations-2.7.4.jar,jackson-core-2.7.4.jar,jackson-databind-2.7.4.jar

在springmvc下配置:

<mvc:annotation-driven conversion-service="conversionService">
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
    </mvc:message-converters>
</mvc:annotation-driven>

8.4json交互测试

以下分别为请求的是json数据,响应的也是json数据和请求key/value数据,响应的json数据的情况

<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.4.4.min.js"></script>
<script type="text/javascript">
    function requestJson(){
        $.ajax({
            url:"${pageContext.request.contextPath }/json/requestJson.action",
            type:"post",
            contentType:"application/json;charset=utf-8",
            //请求json数据,使用json表示商品信息
            data:'{"name":"手机","price":1999}',
            success:function(data){
                alert(data.name);
            }
        });
    }
    function responseJson() {
        $.ajax({
            url:"${pageContext.request.contextPath }/json/responseJson.action",
            type:"post",
            //contentType:"application/json;charset=utf-8",
            //不需要指定contentType,因为默认是key/value型
            //请求key/value数据
            data:"name=手机&price=1999",
            success:function(data){

                alert(data.name);
            }


        });
    }
</script>
@Controller
@RequestMapping("/json")
public class jsonTest {
    @RequestMapping("requestJson")
    public @ResponseBody ItemsCustom requestJson(@RequestBody ItemsCustom itemsCustom) throws Exception{

        return itemsCustom;
    }
    //请求key/value(在页面中通过ajax写入用户想要请求的key/value信息,不需要加@RequestBody注解),响应json(由于action返回的是itemsCustom对象,所以需要加入@ResponseBody注解将pojo对象转换为json格式响应给用户)
    @RequestMapping("/responseJson")
    public @ResponseBody ItemsCustom responseJson(ItemsCustom itemsCustom) throws Exception{

        return itemsCustom;
    }
}

9.restful

9.1什么是restful

RESTful是一种软件开发理念,RESTful对http进行非常好的诠释。RESTful即Representational State Transfer的缩写。

1、 对url进行规范,写restful格式的url

非RESTful的http的url:http://localhost:8080/items/editItems.action?id=1&....

RESTful的url是简洁的:http://localhost:8080/items/editItems/1

2、 http的方法规范

不管是删除、添加、更新。使用url是一致的,如果进行删除,需要设置http的方法为delete,同理添加。。

后台controller方法:判断http方法,如果是delete执行删除,如果是post执行添加

3、 对http的contentType规范

请求时指定contentType,要json数据,设置成json格式的type

9.2需求

根据id查看商品信息,商品信息查看的连接使用RESTful方式实现,商品信息以json返回。

9.3Controller

@RequestMapping("/itemsView/{id}")
public @ResponseBody ItemsCustom itemsView(@PathVariable("id")Integer id) throws Exception{
    ItemsCustom itemsCustom=itemsService.findItemById(id);
    return itemsCustom;
}

9.4rest前端控制器配置

<!--RESTful的配置-->
<servlet>
    <servlet-name>springmvc_rest</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--加载springmvc配置文件-->
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <!--配置文件的地址
        如果不配置contextConfigLocation,默认查找的配置文件名称是classpath下的:servlet名称+"-servlet.xml"即springmvc-servlet.xml-->
        <param-value>classpath:springmvc/springmvc.xml</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>springmvc_rest</servlet-name>
    <!--可以配置/:此工程所有的请求全部由springmvc解析,此种方式可以实现RESTful方式,需要特殊处理对静态文件的解析不能由springmvc解析
    可以配置*.do或者*.action,所有请求的url扩展名为.do或.action由springmvc解析,此中方法常用
    不可以配置/*,如果配置/*,返回jsp也由springmvc解析,这是不对的-->

    <!--rest方式配置为/-->
    <url-pattern>/</url-pattern>
</servlet-mapping>

9.5对静态资源的解析

我们在web.xml中将访问所有路径的方式设置为:<url-pattern>/</url-pattern>即访问只要是该路径下的资源时都会经过前端控制器,这是不对的。当我们访问web包下的静态资源时也会经过前端控制器由springmvc解析,这当然是不正确的。所以我们需要设置静态资源的解析,在springmvc.xml中添加如下配置信息:

<mvc:resources location="/js/" mapping="/js/**"/>

表示访问web/js/包下的静态资源时不会被前端控制器拦截也就不会被springmvc.xml解析。此时便可以正常访问静态资源。

10.拦截器

10.1拦截器的定义

定义拦截器

public class HandlerInterceptor1 implements HandlerInterceptor{
    //在执行handler之前来执行的
    //用于用户认证校验、用户权限校验
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        //返回false表示进行拦截,不继续执行handler。返回true表示不进行拦截,继续执行handler
        return false;
    }
    //在执行handerl但是返回modelandview之前来执行
    //如果需要向页面提供一些公用的数据(菜单的导航)或配置一些视图信息,使用此方法实现从modelAndView入手
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }
    //执行handler之后执行此方法
    //做系统统一异常处理,进行方法执行性能监控,在prehandler中设置一个时间点,在afterCompletion设置一个时间点,两个时间点的差就是执行时长
    //实现系统统一日志记录
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

10.2拦截器配置

  • 针对HandlerMapping进行拦截设置

springmvc拦截器对HandlerMapping进行拦截设置。

如果在某个HandlerMapping中配置拦截,经过该HandlerMapping映射成功的handler最终使用该拦截器。

  • 类似全局的拦截器

springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中

<!--拦截器 -->
<mvc:interceptors>
    <!--多个拦截器,顺序执行 -->
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="interceptor.HandlerInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="interceptor.HandlerInterceptor2"></bean>
    </mvc:interceptor>

</mvc:interceptors>

10.3拦截测试

再定义一个拦截器HandlerInterceptor2.java,代码如下:

public class HandlerInterceptor2 implements HandlerInterceptor{
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        System.out.println("HandlerInterceptor2....postHandle");
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor2....postHandler");
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        System.out.println("HandlerInterceptor2....afterCompletion");
    }
}
  • 两个拦截器都放行

测试结果为:

HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion

总结:执行preHandle是顺序执行。执行postHandle、afterCompletion是倒序执行。

  • 拦截器1放行,2不放行

此时访问界面,界面是空白的但是不会出现报错信息,控制台打印测试结果:

HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor1...afterCompletion

总结:

拦截器1放行,拦截器2才会执行preHandler

如果preHandle不放行,postHandle、afterCompletion都不执行。只要有一个拦截器不放行,postHandler不会执行。

  • 拦截器1和2都不放行

    测试结果:

    HandlerInterceptor1...preHandle
    

在这里插入图片描述

10.4拦截器应用(实现登陆认证)

10.4.1需求

  1. 用户请求url

  2. 拦截器进行拦截校验

    如果请求的url是公开地址(无需登录即可访问的url),让放行

    如果用户session不存在跳转到登录页面

    如果用户session存在放行,继续操作。

10.4.2登录的controller方法

@Controller
public class LoginController {
    //用户登陆提交方法
    @RequestMapping("/login")
    public String login(HttpSession session, String usercode, String password) throws Exception
    {
        //调用service校验用户帐号和密码的正确性
        //这个东西我们讲shiro的时候再写



        //如果service校验通过,将用户身份记录到session
        session.setAttribute("usercode",usercode);

        //重定向到商品查询页面
        return "redirect:/items/queryItems.action";
    }

    //用户退出
    @RequestMapping("/logout")
    public String logout(HttpSession session) throws Exception
    {
        //session失效
        session.invalidate();

        //重定向到商品查询页面
        return "redirect:/items/queryItems.action";
    }
}
发布了151 篇原创文章 · 获赞 110 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_35564813/article/details/104721156