【Java框架】SpringMVC(三)——异常处理,拦截器,文件上传,SSM整合-程序员宅基地

技术标签: spring  Java  架构  java  web  j2ee  后端  开发语言  

异常处理

  • HandlerExceptionResolver
    • resolveException()
  • 局部异常处理
    • 仅能处理指定Controller中的异常
    • @ExceptionHandler

解释

  • Spring MVC 通过HandlerExceptionResolver 处理程序的异常,包括Handler 映射、数据绑定以及目标方法执行时发生的异常。
  • 主要处理Handler 中用@ExceptionHandler 注解定义的方法。
  • ExceptionHandlerMethodResolver 内部若找不到@ExceptionHandler 注解的话, 会找@ControllerAdvice 类的@ExceptionHandler 注解方法, 这样就相当于一个全局异常处理器。

局部异常处理

package cn.smbms.controller;

import cn.smbms.pojo.User;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Map;

/**
 * @author: zjl
 * @datetime: 2024/4/18
 * @desc:
 */
@RestController
public class HelloController {
    
    @GetMapping(value = "/index")
    public String index(){
    
        System.out.println(5/0);//模拟异常
        return "index";
    }

    /**
     * 这里处理ArithmeticException.class,NullPointerException.class类型的异常
     * Exception ex: 生成的异常对象,会传递给ex, 通过ex可以得到相关的异常信息,这里程序员可以加入自己的业务逻辑
     * 这里采用ServletAPI入参,HttpServletRequest、HttpServletResponse、HttpSession...都可以直接用
     */
    @ExceptionHandler({
    ArithmeticException.class,NullPointerException.class})
    public String localException(Exception ex, HttpServletRequest request){
    
        System.out.println("局部异常信息是-" + ex.getMessage());
        //如何将异常的信息带到下一个页面.
        request.setAttribute("errorInfo", ex.getMessage());
        return "error";
    }
}

全局异常

  • 对所有异常进行统一处理
  • 配置SimpleMappingExceptionResolver
    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <!--<prop key="java.lang.NullPointerException">null.jsp</prop>
                <prop key="java.lang.ClassNotFoundException">class.jsp</prop>
                <prop key="java.sql.SQLException">sql.jsp</prop>
                <prop key="java.io.IOException">io.jsp</prop>-->
                <prop key="java.lang.RuntimeException">error</prop>
            </props>
        </property>
    </bean>

拦截器

在这里插入图片描述

  1. 浏览器发送一个请求会先到Tomcat的web服务器
  2. Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源
  3. 如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问
  4. 如果是动态资源,就需要交给项目的后台代码进行处理
  5. 在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行
  6. 然后进入到到中央处理器(SpringMVC中的内容),SpringMVC会根据配置的规则进行拦截
  7. 如果满足规则,则进行处理,找到其对应的controller类中的方法进行执行,完成后返回结果
  8. 如果不满足规则,则不进行处理

这个时候,如果我们需要在每个Controller方法执行的前后添加业务,具体该如何来实现?——拦截器

拦截器介绍

拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

作用:

  • 在指定的方法调用前后执行预先设定的代码
  • 阻止原始方法的执行
  • 总结:拦截器就是用来做增强

拦截器和过滤器之间的区别

  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强
    在这里插入图片描述

拦截器执行流程

在这里插入图片描述

代码实现

自定义拦截器类

package cn.smbms.interceptor;

import cn.smbms.tools.Constants;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author: zjl
 * @datetime: 2024/4/12
 * @desc:
 */
public class SysInterceptor extends HandlerInterceptorAdapter {
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
        Object obj = request.getSession().getAttribute(Constants.USER_SESSION);
        if(obj == null){
    
            //未登录,重定向到401.jsp
            response.sendRedirect(request.getContextPath() + "/401.jsp");
            return false;
        }
        return true;
    }
}

配置拦截规则

    <!-- 配置拦截器interceptors -->
    <mvc:interceptors>
        <mvc:interceptor>
            <mvc:mapping path="/**"/><!-- 配置拦截规则 -->
            <mvc:exclude-mapping path="/login.do"/><!-- 配置不拦截规则 -->
            <mvc:exclude-mapping path="/logout"/><!-- 配置不拦截规则 -->
            <bean class="cn.smbms.interceptor.SysInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

补充

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作
    在这里插入图片描述

preHandle:与配置顺序相同,必定运行

postHandle:与配置顺序相反,可能不运行

afterCompletion:与配置顺序相反,可能不运行。

文件上传

  • MultipartResolver接口
    • 用于处理上传请求,将上传请求包装成可以直接获取文件的数据,方便操作
  • 两个实现类
    • StandardServletMultipartResolver
      • 使用了Servlet3.0标准的上传方式
    • CommonsMultipartResolver
      • 使用了Apache的commons-fileupload来完成具体的上传操作

依赖

	<!-- 文件上传 -->
	<dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.8.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.6</version>
    </dependency>
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>

配置MultipartResolver

    <!-- 配置MultipartResolver,用于上传文件,使用spring的CommonsMultipartResolver -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="5000000"/><!-- 上传文件大小上限,单位为字节-- >
        <property name="defaultEncoding" value="UTF-8"/><!-- 请求的编码格式,默认为ISO-8859-1,此处设置为UTF-8 -->
    </bean>

编写文件上传表单页

  • method=“POST”
  • enctype=“multipart/form-data”
    • 指定表单内容类型,支持文件上传
  • <input type=“file” name=“a_idPicPath”/>
    • 用来上传文件的file组件

API

MultipartFile

  • Spring MVC会将上传文件绑定到MultipartFile对象中,并通过该对象完成文件的上传操作

File.separator

  • Windows、Linux自适应路径分隔符
  • 低入侵性的代码实现

必须对上传文件进行重命名

原因

  • 原文件名存在中文 乱码问题
  • 原文件名与服务器上已有文件重名 覆盖问题

重新定义上传文件名(保证不重名)

  • 当前系统时间+随机数+“_Personal.jpg”

文件上传成功后,须更新数据库字段(idPicPath),记录上传文件的存储路径

代码示例

	//文件上传
	@RequestMapping(value="/useraddsave.html",method=RequestMethod.POST)
	public String addUserSave(User user,HttpSession session,HttpServletRequest request,
							 @RequestParam(value ="a_idPicPath", required = false) MultipartFile attach){
    
		String idPicPath = null;
		//判断文件是否为空
		if(!attach.isEmpty()){
    
			String path = request.getSession().getServletContext().getRealPath("statics"+File.separator+"uploadfiles"); 
			logger.info("uploadFile path ============== > "+path);
			String oldFileName = attach.getOriginalFilename();//原文件名
			logger.info("uploadFile oldFileName ============== > "+oldFileName);
			String prefix=FilenameUtils.getExtension(oldFileName);//原文件后缀     
	        logger.debug("uploadFile prefix============> " + prefix);
			int filesize = 500000;
			logger.debug("uploadFile size============> " + attach.getSize());
	        if(attach.getSize() >  filesize){
    //上传大小不得超过 500k
            	request.setAttribute("uploadFileError", " * 上传大小不得超过 500k");
	        	return "useradd";
            }else if(prefix.equalsIgnoreCase("jpg") || prefix.equalsIgnoreCase("png") 
            		|| prefix.equalsIgnoreCase("jpeg") || prefix.equalsIgnoreCase("pneg")){
    //上传图片格式不正确
            	String fileName = System.currentTimeMillis()+RandomUtils.nextInt(1000000)+"_Personal.jpg";  
                logger.debug("new fileName======== " + attach.getName());
                File targetFile = new File(path, fileName);  
                if(!targetFile.exists()){
      
                    targetFile.mkdirs();  
                }  
                //保存  
                try {
      
                	attach.transferTo(targetFile);  
                } catch (Exception e) {
      
                    e.printStackTrace();  
                    request.setAttribute("uploadFileError", " * 上传失败!");
                    return "useradd";
                }  
                idPicPath = path+File.separator+fileName;
            }else{
    
            	request.setAttribute("uploadFileError", " * 上传图片格式不正确");
            	return "useradd";
            }
		}
		user.setCreatedBy(((User)session.getAttribute(Constants.USER_SESSION)).getId());
		user.setCreationDate(new Date());
		user.setIdPicPath(idPicPath);
		if(userService.add(user)){
    
			return "redirect:/user/userlist.html";
		}
		return "useradd";
	}

省略service、mapper、sql代码

SpringMVC文件上传流程

在这里插入图片描述

多文件上传

<label for="a_idPicPath">证件照:</label>
<input type="file" name="attachs" id="a_idPicPath"/>
<label for="a_workPicPath">工作证照片:</label>
<input type="file" name="attachs" id="a_workPicPath"/>
  • 控制器-处理方法addUserSave()
    • 修改入参MultipartFile为数组
      • MultipartFile[] attachs
  • MultipartFile[] 数组内存放文件对象顺序
    • 按照form表单的file标签的顺序进行存储
  • 分别更新字段:idPicPath、workPicPath
  • 若入参对象MultipartFile为数组时,该参数前面必须要加上@RequestParam注解,否则会报错
@RequestParam(value="a_idPicPath",required=false) 		    							MultipartFile idPicFile,
@RequestParam(value="a_workPicPath",required=false)
                                            MultipartFile workPicFile)

静态资源加载

1.将静态资源统一放在一个路径下

在这里插入图片描述

2.配置静态资源加载

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

SSM整合

  • 1.使用IDEA创建SSM的Maven工程
  • 2.在main目录中创建出来java和resources目录
  • 3.修改pom.xml
    • 3.1导入SSM使用的依赖
    • 3.2导入resources配置
    • 3.3对maven工程重新构建(reload project)
  • 4.创建package目录结构,基本目录命名规则:com.项目名简称
    实体类:entity或pojo
    请求层:controller
    业务层:service
    数据访问层:mapper
    工具类包:utils或tools
    配置类包:config
    过滤器包:filter
    拦截器包:interceptor
  1. 导入SSM使用的配置文件,放在resources目录下
  • 5.1spring配置文件:applicationContext.xml【修改扫描的包路径】
  • 5.2springMvc配置文件:springm-servlet.xml【修改扫描的包路径,去掉没用的配置】
  • 5.3创建mybatis目录,导入mybatis配置文件:mybatis-config.xml【修改实体类别名的包名】
  • 5.4在mybatis目录下创建mapper目录
  • 5.5将写SQL的mapper.xml导入进来,修改为对应实体类的mapper.xml【修改namespace的路径】
  • 5.6数据库配置文件:database.properties【修改数据库连接信息】
  • 5.7日志配置文件:log4j.properties
  • 5.8web.xml配置文件:修改启动页“welcome-file”、引入spring、springmvc、过滤器的配置
  • 5.9注意:修改配置文件中的自定义配置(包名、路径名等)
  • 6.编写java代码
    pojo——controller——service——mapper——mapper.xml
  • 7.编写前端页面
    • 将前端页面统一放在一个目录下(jsp),以便配置视图解析器,在请求层可以直接使用逻辑视图名。
  • 8.编写/导入静态资源
    • 图片、音频、视频、样式、js、插件等等
    • 注意:将静态资源统一放在webapp/statics下
    • 若没有statics目录需要手动创建。
  • 9.在springm-servlet.xml中配置静态资源访问,否则无法使用静态资源
  • 10.在编写完请求层、业务逻辑层、以及SQL后,可以进行功能测试
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_37833693/article/details/137972016

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文