目录
- 异常处理
- 解释
- 局部异常处理
- 全局异常
- 拦截器
- 拦截器介绍
- 作用:
- 拦截器和过滤器之间的区别
- 拦截器执行流程
- 代码实现
- 补充
- 文件上传
- 依赖
- 配置MultipartResolver
- 编写文件上传表单页
- API
- MultipartFile
- File.separator
- 必须对上传文件进行重命名
- 代码示例
- SpringMVC文件上传流程
- 多文件上传
- 静态资源加载
- 1.将静态资源统一放在一个路径下
- 2.配置静态资源加载
- SSM整合
异常处理
- 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>
拦截器
- 浏览器发送一个请求会先到Tomcat的web服务器
- Tomcat服务器接收到请求以后,会去判断请求的是静态资源还是动态资源
- 如果是静态资源,会直接到Tomcat的项目部署目录下去直接访问
- 如果是动态资源,就需要交给项目的后台代码进行处理
- 在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行
- 然后进入到到中央处理器(SpringMVC中的内容),SpringMVC会根据配置的规则进行拦截
- 如果满足规则,则进行处理,找到其对应的controller类中的方法进行执行,完成后返回结果
- 如果不满足规则,则不进行处理
这个时候,如果我们需要在每个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来完成具体的上传操作
- StandardServletMultipartResolver
依赖
<!-- 文件上传 -->
<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为数组
- 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
…
- 导入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后,可以进行功能测试