spring MVC(下)

1、设置拦截器
对于 SpringMVC 拦截器的定义⽅式有两种:
实现接⼝:
org.springframework.web.servlet.HandlerInterceptor

继承适配器:
org.springframework.web.servlet.handler.HandlerInterceptorAdapter

实现 HandlerInterceptor 接⼝
MyInterceptor01.java实现HandelerInterceptor接口

public class MyInterceptor01  implements HandlerInterceptor {

    /**
     * 在 ⽬标Handler(⽅法)执⾏前 执⾏
     * 返回 true:执⾏handler⽅法
     * 返回 false:阻⽌⽬标handler⽅法执⾏
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        System.out.println("⽬标Handler执⾏前执⾏MyInterceptor01 --> preHandle⽅法...");
        /**
         * 返回 true:执⾏handler⽅法
         * 返回 false:阻⽌⽬标handler⽅法执⾏
         */
        return false;
    }

    /*
    * 在 ⽬标Handler(⽅法)执⾏后,视图⽣成前 执⾏
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {

        System.out.println("⽬标Handler执⾏后,视图⽣成前执⾏ --> postHandle⽅法...");

    }

    /*
    在 ⽬标Handler(⽅法)执⾏后,视图⽣成后 执⾏
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {

        System.out.println("⽬标Handler执⾏后,视图⽣成后执⾏ --> afterCompletion⽅法...");
    }
}

接下来配置下servlet-context.xml

    <!-- 拦截器配置:⽅式⼀ -->
    <mvc:interceptors>
        <!--
        使⽤bean定义⼀个Interceptor
        直接定义在mvc:interceptors根下⾯的Interceptor将拦截所有的请求
        -->
        <bean class="com.shsxt.springmvc.interceptor.MyInterceptor01"/>
    </mvc:interceptors>
---------------------------------------------------------
    <!-- 拦截器配置:⽅式⼆ (推荐使⽤) -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 通过 mvc:mapping 配置需要拦截的资源。⽀持通配符。可配置多个。 -->
            <mvc:mapping path="/**"/>
            <!-- 通过 mvc:mapping 配置不需要被拦截的资源。⽀持通配符。可配置多个。 -->
            <mvc:exclude-mapping path="/url/*"/><!-- "/url/*"表示放⾏url路径下的请求。 -->
            <bean class="com.shsxt.springmvc.interceptor.MyInterceptor01"/>
        </mvc:interceptor>
    </mvc:interceptors>

继承HandlerInterceptorAdapter
MyInterceptor02.java

public class MyInterceptor02  extends HandlerInterceptorAdapter {

  		/**
         * 返回 true:执⾏handler⽅法
         * 返回 false:阻⽌⽬标handler⽅法执⾏
         */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("MyInterceptor02拦截器.....");
        return true;
    }
}

配置下servlet-context.xml

   <!-- 拦截器配置:(推荐使⽤) -->
    <mvc:interceptors>
        <mvc:interceptor>
            <!-- 通过 mvc:mapping 配置需要拦截的资源。⽀持通配符。可配置多个。 -->
            <mvc:mapping path="/**"/>
            <!-- 通过 mvc:mapping 配置不需要被拦截的资源。⽀持通配符。可配置多个。 -->
            <mvc:exclude-mapping path="/url/*"/><!-- "/url/*"表示放⾏url路径下的请求。 -->
            <bean class="com.shsxt.springmvc.interceptor.MyInterceptor02"/>
        </mvc:interceptor>
    </mvc:interceptors>

2、多个拦截器实现
SpringMVC 框架⽀持多个拦截器配置,从⽽构成拦截器链,对客户端请求进⾏多次拦截操作。
这⾥参考MyInterceptor01、MyInterceptor02代码

拦截器链
            当多个拦截器同时生效时,构成拦截器链
            执行顺序:
                preHandle方法:先配置的先执行
                postHandle方法:先配置的后执行
                afterCompletion方法:先配置的后执行

3、拦截器应⽤ - ⾮法请求拦截
简单的登录测试
准备一个UserLoginController.java

@Controller
@RequestMapping("user")
public class UserLoginController {

    @RequestMapping("/login")
    public String login(HttpServletRequest request) {

        request.setAttribute("msg","用户登录...");

        // 设置session作用域,用来标识用户的登录状态
        request.getSession().setAttribute("user","admin");

        return "success";
    }
    @RequestMapping("/add")
    public  String add(HttpServletRequest request){

        request.setAttribute("msg","用户添加");
        return "success";
    }
    @RequestMapping("/update")
    public  String update(HttpServletRequest request){

        request.setAttribute("msg","用户修改");
        return "success";
    }
    @RequestMapping("/delete")
    public  String delete(HttpServletRequest request){

        request.setAttribute("msg","用户删除");
        return "success";
    }
}

再准备一个登录的拦截器
LoginInterceptor.java

public class LoginInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //如果用户未登录,则拦在登录页面
        //获取session作用域的值(如果值为空,则未登录状态,否则为登录状态)
        String msg = (String) request.getSession().getAttribute("user");
        //如果session为空,表示未登录,拦截在登录页面
        if (msg==null){
            //重定向到登录页面
            response.sendRedirect(request.getContextPath() + "/login.jsp");
            return  false;
        }
        //否则登录状态,执行放行的资源
        return true;
 }
}

设置一下拦截器
servle-context.xml

mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <mvc:exclude-mapping path="/user/login"/>
            <bean class="com.shsxt.springmvc.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

准备一个登录页面
login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>拦截器应用</title>
</head>
<body>

<h3>用户登录</h3>
<form action="user/login" >
    <button>登录</button>
</form>
</body>
</html>

最后准备一个成功页面
success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
</head>
<body>
<h3>${msg}</h3>
</body>
</html>

这样就可以测试了

4、MultipartFile实现文件上传
MultipartFile类是一个接口,文件内容存储在内存中或临时存储在磁盘上。在任何一种情况下,如果需要,用户负责将文件内容复制到会话级或持久性存储。临时存储将在请求处理结束时清除。

首先添加commons-fileupload 依赖

<!-- 添加 commons-fileupload 依赖 -->
<dependency>
 <groupId>commons-fileupload</groupId>
 <artifactId>commons-fileupload</artifactId>
 <version>1.3.2</version>
</dependency>

然后修改servlet-context.xml
注意拦截器,要么放行资源,要么删除拦截器

<!-- ⽂件上传 -->
<bean id="multipartResolver"
 class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
 <!-- 允许⽂件上传的最⼤尺⼨ -->
 <property name="maxUploadSize">
 <value>104857600</value>
 </property>
 <!--
 设置⽂件放⼊临时⽂件夹的最⼤⼤⼩限制。
 此值是阈值,低于此值,则保存在内存中,如⾼于此值,则⽣成硬盘上的临时⽂件。
 -->
 <property name="maxInMemorySize">
 <value>4096</value>
 </property>
</bean>

接下来就可以写代码了,将逻辑代码封装起来,直接调用即可

单文件上传
FileController.java

/**
 * ⽂件上传
 */
@Controller
public class FileController {

    /**
     * 单⽂件上传
     * 使⽤MultipartFile对象作为参数,接收前端发送过来的⽂件
     */
    @RequestMapping("uploadFile")
    public  String uploadFile(@RequestParam("myfile") MultipartFile multipartFile, HttpServletRequest request) {

        saveFile(multipartFile,request);
        return "upp";
    }
  /*
 逻辑判断
  */
  public void saveFile(MultipartFile multipartFile,HttpServletRequest request) {
         //拿到文件后需要对文件进行一些操作
        // 判断上传的文件是否为空
      if (multipartFile.isEmpty()){
        // 设置请求域
       request.setAttribute("msg","请选择要上传的文件");
            }else {
                //上传文件不能为空
                //得到项目所在的路径
                String realPath=request.getServletContext().getRealPath("/");
                // 设置文件到指定目录下
                File filePath = new File(realPath+"/upload");
                // 判断目录是否存在,不存在则新建目录
                if (!filePath.exists()){
                    //不存在,则新建文件夹
                    filePath.mkdir();
                }

                try {
        // 得到上传文件的文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 得到文件名的后缀
        String safx =originalFilename.substring(originalFilename.lastIndexOf("."));
            // 生成随机文件名    文件名拼接
           String fileName =System.currentTimeMillis()+safx;
            //转存文件
            multipartFile.transferTo(new File(filePath,fileName));
                    //成功
                 request.setAttribute("msg","文件上传成功!!!");
                } catch (IOException e) {
                    e.printStackTrace();
                    //失败
            request.setAttribute("msg","文件上传失败!!!");
                }
            }
        }
}

前端页面
upload.jsp

 <%--设置提交方式post,设置表单类型enctype="multipart/form-data--%>
<form action="uploadFile" method="post" enctype="multipart/form-data">
    文件: <input type="file" name="myfile"/>
<button> 提交</button>
</form>

upp.jsp
请求域

${msg}

多文件上传
FileController.java 逻辑代码封装起来,直接调用即可

 /*
    多文件上传
     */
    @RequestMapping("/files")
    public String uploadFiles(@RequestParam("files")List<MultipartFile>  multipartFile , HttpServletRequest request){
        // 判断集合是否为空
      if (multipartFile!=null&&multipartFile.size()>0){
        for (MultipartFile list: multipartFile){
            saveFile(list,request);
        }
      }
      return  "upp";
    }

前端页面
upload.jsp

<form action="files" method="post" enctype="multipart/form-data">
    多文件:<input type="file" name="files"/>
    <input type="file" name="files"/>
    <input type="file" name="files"/>
     <button>提交</button>

请求域

${msg}

5、了解Restful风格
REST – REpresentational State Transfer 直译:表现层状态转移。Restful就是一个资源定位及资源操作的风格。不是标准也不是协议,只是一种风格。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制

URL定义
⽤户请求的 url 使⽤同⼀个 url
请求⽅式:get,post,delete,put…等对请求的处理⽅法进⾏区分
这样可以在前后台分离式的开发中使得前端开发⼈员不会对请求的资源地址产⽣混淆和⼤量的检查⽅法名的麻烦,形成⼀个统⼀的接⼝。

有规定如下:

  • GET(SELECT):从服务器查询,可以在服务器通过请求的参数区分查询的⽅式。
  • POST(CREATE):在服务器端新建⼀个资源,调⽤ insert 操作。
  • PUT(UPDATE):在服务器端更新资源,调⽤ update 操作。
  • PATCH(UPDATE):在服务器端更新资源(客户端提供改变的属性)。(⽬前 jdk7 未实现,tomcat7不⽀持)。
  • DELETE(DELETE):从服务器端删除资源,调⽤ delete 语句。

@PathVariable

  • 带占位符的 URL 是 Spring3.0 新增的功能,该功能在SpringMVC 向 REST 目标挺进发展过程中具有里程碑的意义
  • 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx}占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。(形参要一致)
	 @DeleteMapping("account/{accountId}")
     @ResponseBody
    public Map<String, Object> deleteAccount(@PathVariable Integer accountId) {

        int row = accountService.deleteAccount(accountId);

        Map<String, Object> map = new HashMap<>();

        if (row > 0) {
            map.put("code", 1);
            map.put("msg","删除成功!");
        } else {
            map.put("code", 0);
            map.put("msg","删除失败!");
        }

        return map;
    }

@RequestParam与@PathVariable

@RequestParam和@PathVariable都能够完成类似的功能——因为本质上,它们都是用户的输入,只不过输入的部分不同,一个在URL路径部分,另一个在参数部分。
1、当URL指向的是某一具体业务资源(或资源列表),例如博客,用户时,使用@PathVariable

2、当URL需要对资源或者资源列表进行过滤,筛选时,用@RequestParam

6、全局异常统⼀处理
SpringMVC 对于异常处理这块提供了⽀持,通过 SpringMVC 提供的全局异常处理机制,能够将所有类型的异常处理从各处理过程解耦出来,既保证了相关处理过程的功能较单⼀,也实现了异常信息的统⼀处理和维护。

全局异常实现⽅式 Spring MVC 处理异常有 3 种⽅式:

  • 使⽤ Spring MVC 提供的简单异常处理SimpleMappingExceptionResolver
  • 实现 Spring 的异常处理接⼝ HandlerExceptionResolver ⾃定义⾃⼰的异常处理器
  • 使⽤ @ExceptionHandler 注解实现异常处理

全局异常处理⽅式⼀:
i、 配置简单异常处理器
在servlet-context.xml中配置 SimpleMappingExceptionResolver 对象

servlet-context.xml

<!-- 配置全局异常统⼀处理的 Bean (简单异常处理器) -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
 <!-- ⻚⾯在转发时出现异常,设置默认的错误⻚⾯ (error代表的是⼀个视图) -->
 <property name="defaultErrorView" value="error"></property>
 <!-- 异常发⽣时,设置异常的变量名 -->
 <property name="exceptionAttribute" value="ex"></property>
</bean>

error.jsp

<h3>异常页面</h3>
${ex}

ii、⾃定义异常
准备来个异常类
参数异常------继承RuntimeException

public class ParamsException extends RuntimeException {
 private Integer code = 300;
 private String msg = "参数异常!";
 }
 //get、set、方法省略

业务异常------继承RuntimeException

public class BusinessException extends RuntimeException {
 private Integer code=400;
 private String msg="业务异常!";
 }

设置⾃定义异常与⻚⾯的映射

<!--设置自定义异常与页面映射-->
  <property name="exceptionMappings">
     <props>
        <!--自定义异常对象的路径,标签中设置具体的处理页面的视图名-->
  <prop key="com.shsxt.ssm.exception.BusinessException">buerror</prop>
  <prop key="com.shsxt.ssm.exception.ParamsException">paerror</prop>
    </props>
    </property>

准备两个前端页面,用来做页面显示的
buerror.jsp

<h3>业务异常</h3>

paerror.jsp

<h3>参数异常</h3>

测试:
准备一个抛异常行为

if(true) {
  throw new BusinessException();
   }

总结:
使⽤ SimpleMappingExceptionResolver 进⾏异常处理,具有集成简单、有良好的扩展性、对已有代码没有⼊侵性等优点,但该⽅法仅能获取到异常信息,若在出现异常时,对需要获取除异常以外的数据的情况不适⽤。

全局异常处理⽅式二:(推荐)

实现 HandlerExceptionResolver 接⼝

GlobalExceptionResolver.java

@Component
public class GlobalExceptionResolver implements HandlerExceptionResolver {
    @Override
    public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {

        ModelAndView modelAndView = new ModelAndView("error");

        modelAndView.addObject("mg","默认错误信息");

        // 判断是否是⾃定义异常
        if (e instanceof ParamsException){
            modelAndView.setViewName("paerror");
            ParamsException paramsException= (ParamsException) e;
            modelAndView.addObject("mg",((ParamsException) e).getMsg());
        }

        if (e instanceof BusinessException){
            modelAndView.setViewName("buerror");
            BusinessException businessException= (BusinessException) e;
            modelAndView.addObject("mg",((BusinessException) e).getMsg());
        }
        return modelAndView;
    }
}

准备两个前端页面,用来做页面显示的
buerror.jsp

<h3>业务异常</h3>
${mg}

paerror.jsp

<h3>参数异常</h3>
${mg}

配置文件还是一样
测试:

if(true) {
  throw new BusinessException();
   }

全局异常处理⽅式三:
使⽤ @ExceptionHandler 注解实现异常处理
⻚⾯处理器继承 BaseController
准备一个BaseController.java

public class BaseController  {
/*
表示该方法是用来处理异常的
 */
    @ExceptionHandler
    public String exc(HttpServletRequest request , HttpServletResponse response , Object o, Exception e){

        request.setAttribute("mg",e);

        if (e instanceof ParamsException){
            request.setAttribute("mg",((ParamsException) e).getMsg());
        }
        if (e instanceof BusinessException){
            request.setAttribute("mg",((BusinessException) e).getMsg());
        }
        return "error";
    }
}

HelloController.java

@Controller
public class HelloController extends BaseController{

    @Autowired
    private UserService userService;

    @RequestMapping("/hello")
    public ModelAndView hello() {

       if(true) {
          throw new BusinessException();
    }
        ModelAndView modelAndView = new ModelAndView();

        //调用service  层查询方法
        User user = userService.queryUserById(1);

        modelAndView.addObject("user",user);

        modelAndView.setViewName("hello");
        return modelAndView;
    }
}

总结:
使⽤ @ExceptionHandler 注解实现异常处理,具有集成简单、有扩展性好(只需要将要异常处理的Controller 类继承于 BaseController 即可)、不需要附加Spring 配置等优点,但该⽅法对已有代码存在⼊侵性(需要修改已有代码,使相关类继承于 BaseController),在异常处理时不能获取除异常以外的数据。

7、未捕获异常的处理

由于代码不强制捕获,往往被忽略,如果运⾏期产⽣了Unchecked
Exception,⽽代码中⼜没有进⾏相应的捕获和处理。

此时需要⼀个全⾯⽽有效的异常处理机制。⽬前⼤多数服务器也都⽀持在 web.xml 中通过(Websphere/Weblogic)或者(Tomcat)节点配置特定异常情况的显示⻚⾯。修改 web.xml ⽂件

web.xml

<!-- 出错⻚⾯定义 -->
<error-page>
 <exception-type>java.lang.Throwable</exception-type>
 <location>/500.jsp</location>
</error-page> <error-page>
 <error-code>500</error-code>
 <location>/500.jsp</location>
</error-page> <error-page>
 <error-code>404</error-code>
 <location>/404.jsp</location>
</error-page>

准备前端响应页面
500.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>错误页面</title>
</head>
<body>
<h1>500</h1>
</body>
</html>

其他的都类似。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值