Bootstrap

Spring MVC 数据校验及文件上传

数据校验及文件上传

文章目录

1.预习与目标

1.1预习检查
  1. 在Spring MVC中,如何处理多文件上传?

  2. 在Spring MVC中,如何实现服务端的数据验证?

  3. 怎么使用@PathVariable注解?

  4. 什么是REST风格

1.2学习目标
  1. 掌握REST风格API

  2. 掌握数据验证框架-JSR303

  3. 掌握Spring标签

  4. 掌握Spring MVC框架的单文件、多文件上传技术


2.改造添加用户功能

2.1添加用户功能—需求

需求:

  • 改造724系统-用户添加功能
  • 登录系统后,进入用户管理模块的用户列表页面,点击添加用户按钮,进入添加用户界面

在这里插入图片描述

2.2添加用户功能—思路分析

分析:

  • 1.输入项

    • 账号、真实姓名、密码、性别、出生日期、手机号码、地址、角色 新增用户的ID
    • 成功保存数据后,页面直接跳转到用户列表页,并在列表页中显示新增数据
  • 2.点击返回按钮,页面跳转到用户列表页面

2.3添加用户功能—实现过程

实现:

1. 改造Controller层:SysUserController中创建两个接口

  • "/toAdd":用于跳转到添加用户页面
  • "/add":接受前端发送的用户数据,调用业务层方法进行保存
    • 接口使用 SysUser 对象接收用户信息
    • 需要访问 session 中的当前登录用户信息

2. 改造View层

  • add.jsp (Ajax相关的功能暂不实现)
  • 修改用户列表页面的添加用户按钮,指向/toAdd接口

3. 注意:

  • 新增用户信息时,需要保存创建人ID(createdUserId)和创建时间(createdTime)两个字段,分别为当前登录用户id和系统当前时间,创建时间的赋值操作在业务层处理。
2.4添加用户功能—存在的缺陷

问题:

  • 输入新增用户信息,点击保存之后系统报错,怎么解决?

    • 400状态码:客户端发送的请求格式不正确

    在这里插入图片描述

    • 控制台:BindException异常:

      17-May-2022 20:17:30.702 警告 [http-nio-8080-exec-2] org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver.logException Resolved [org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors<EOL>Field error in object 'sysUser' on field 'birthday': rejected value [2000-05-25]; codes [typeMismatch.sysUser.birthday,typeMismatch.birthday,typeMismatch.java.util.Date,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [sysUser.birthday,birthday]; arguments []; default message [birthday]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Date' for property 'birthday'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.util.Date] for value '2000-05-25'; nested exception is java.lang.IllegalArgumentException]]

分析:

  • SysUser对象的birthday字段绑定失败
    • SysUser类中定义为java.util.Date类型,页面中添加的却是String类型

解决方案:

  • @DateTimeFormat注解
2.5添加用户功能—示例代码

1. 改造Controller层:SysUserController中创建两个接口

  • "/toAdd":用于跳转到添加用户页面

  • "/add":接受前端发送的用户数据,调用业务层方法进行保存

    • 接口使用SysUser对象接收用户信息
    • 需要访问session中的当前登录用户信息

    @Controller
    @RequestMapping(“/user”)
    public class SysUserController {
    private Logger logger = Logger.getLogger(SysUserController.class);

    /**

    • 跳转到添加用户页面
    • @return
      */
      @GetMapping(“/toAdd”)
      public String toAdd(){
      return “sysUser/add”;
      }

    /**

    • 添加用户
    • @return
      */
      @PostMapping(“/add”)
      public String add(SysUser sysUser , HttpSession session){
      sysUser.setCreatedUserId(((SysUser)session.getAttribute(Constants.USER_SESSION)).getId());
      if(sysUserService.add(sysUser)){
      return “redirect:/user/list”;
      }
      return “sysUser/add”;
      }
      @RequestMapping(value=“/toSysError”)
      public String sysError(){
      return “sysError”;
      }
      }

2. 改造View层

  1. add.jsp(Ajax相关的功能暂不实现)

  2. 修改用户列表页面的添加用户按钮,指向/toAdd接口

    添加

    <%@ page language=“java” contentType=“text/html; charset=UTF-8” pageEncoding=“UTF-8” %>
    <%@include file=“/WEB-INF/jsp/common/head.jsp” %>

    当前位置: 用户管理页面 >> 用户添加页面
    女 男
    系统管理员 经理 普通用户
    <%@include file="/WEB-INF/jsp/common/foot.jsp" %>

3.改造实体类SysUser

package com.aiden.springmvc.cvs.pojo;

import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * SysUser类
*
 * @author Aiden
*/
public class SysUser {
 private Integer id;            //id
 private String account;        //用户编码
 private String realName;       //用户名称
 private String password;       //用户密码
 private Integer sex;           //性别
 @DateTimeFormat(pattern = "yyyy-MM-dd")
 private Date birthday;         //出生日期
 private String phone;          //电话
 private String address;        //地址
 private Integer roleId;        //用户角色
 private Integer createdUserId; //创建者
 private Date createdTime;      //创建时间
 private Integer updatedUserId; //更新者
 private Date updatedTime;      //更新时间

 private String roleIdName;     //扩展属性角色名称
 private Integer age;		   //扩展属性年龄
 //省略getter/setter...

4.dao接口/dao实现

public interface SysUserDao {
    /**
     * 增加用户信息
     * @param connection 数据库连接对象
     * @param sysUser 用户对象
     */
    int insert(Connection connection, SysUser sysUser) throws Exception;
}


@Repository
public class SysUserDaoImpl implements SysUserDao {
    @Override
    public int insert(Connection connection, SysUser sysUser) throws Exception {
        PreparedStatement stmt = null;
        int updateRows = 0;
        if (null != connection) {
            String sql = "insert into t_sys_user (account,realName,password,roleId,sex,birthday,phone,address,createdTime,createdUserId) values(?,?,?,?,?,?,?,?,?,?)";
            Object[] params = {sysUser.getAccount(), sysUser.getRealName(), sysUser.getPassword(),
                    sysUser.getRoleId(), sysUser.getSex(), sysUser.getBirthday(),
                    sysUser.getPhone(), sysUser.getAddress(), sysUser.getCreatedTime(), sysUser.getCreatedUserId()};
            updateRows = BaseDao.execute(connection, stmt, sql, params);
            BaseDao.closeResource(null, stmt, null);
        }
        return updateRows;
    }
}

5.service接口/service实现

/**
 * 业务接口
 * @author Aiden
 */
public interface SysUserService {
    /**
     * 增加用户信息
     *
     * @param user
     * @return
     */
    boolean addUser(SysUser user);
}


/**
 * service业务层捕获异常,进行事务处理
 * 事务处理:调用不同dao的多个方法,必须使用同一个connection(connection作为参数传递)
 * 事务完成之后,需要在service层进行connection的关闭,在dao层关闭(PreparedStatement和ResultSet对象)
 *
 * @author Aiden
 */
@Service
public class SysUserServiceImpl implements SysUserService {
    @Resource
    private SysUserDao userDao;
    @Override
    public boolean addUser(SysUser user) {
        boolean flag = false;
        Connection connection = null;
        try {
            user.setCreatedTime(new Date());
            connection = BaseDao.getConnection();
            connection.setAutoCommit(false);//开启JDBC事务管理
            int updateRows = userDao.insert(connection, user);
            connection.commit();//提交事务
            if (updateRows > 0) {
                flag = true;
                System.out.println("新增成功!");
            } else {
                System.out.println("新增失败!");
            }
        } catch (Exception e) {
            e.printStackTrace();
            try {
                System.out.println("rollback 回滚事务");
                connection.rollback();
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
        } finally {
            //在service层进行connection连接的关闭
            BaseDao.closeResource(connection, null, null);
        }
        return flag;
    }
}

6.新增成功后:

在这里插入图片描述


3.REST风格

3.1REST风格
  • Representational State Transfer,表述性状态转移,是一种流行的软件架构规范

  • 传统URL和REST风格URL的对比

    • /user/view?id=2 VS /user/view/2
    • /user/delete?id=2 VS /user/delete/2
    • /user/update?id=2 VS /user/update/2
  • 可以基于同一资源链接,如"/user/2",通过不同请求方式来区别不同操作

    • GET 查询
    • POST 添加
    • PUT 修改
    • DELETE 删除
3.2改造查询功能

需求说明

  1. 改造724系统-根据用户id查询用户详情
  2. 使用REST风格

实现步骤

  1. 改造Controller层:SysUserController中添加查询详情的接口

    /**

    • 查询用户详情
    • @param id
    • @param model
    • @return
      */
      @GetMapping(“/view/{id}”)
      //@GetMapping(“/{id}”)
      //@GetMapping(“/{id}/view”)
      public String view(@PathVariable String id,Model model){
      logger.debug(“根据id查询用户详情”+id);
      SysUser sysUser = sysUserService.getUserById(id);
      model.addAttribute(sysUser);
      return “sysUser/view”;
      }
  2. 改造View层

    • view.jsp 修改用户列表页面的查看按钮,指向Controller中相关接口

    查看


3.改造编辑功能

3.1演示案例

需求说明

  • 改造724系统-根据用户id修改用户信息

实现步骤

1.改造Controller层:SysUserController中新增跳转到编辑页面接口

  • 查找出要修改的用户信息

    修改修改

    /**

    • 跳转到修改用户页面
    • @param uid
    • @param model
    • @return
      */
      @GetMapping(“/toUpdate”)
      public String toUpdate(@RequestParam String uid,Model model){
      logger.debug(“跳转到修改用户信息页面”);
      SysUser sysUser = sysUserService.getUserById(uid);
      model.addAttribute(sysUser);
      return “sysUser/update”;
      }

2.改造View层

  • 修改用户列表页面的编辑按钮,指向Controller中相关接口

  • 增加编辑用户页面update.jsp

    <%@ page language=“java” contentType=“text/html; charset=UTF-8”
    pageEncoding=“UTF-8” %>
    <%@include file=“/WEB-INF/jsp/common/head.jsp” %>

    当前位置: 用户管理页面 >> 用户修改页面
    女 男 女 男
            <div>
                <label for="phone">手机号码:</label>
                <input type="text" name="phone" id="phone" value="${sysUser.phone }">
                <font color="red"></font>
            </div>
            <div>
                <label for="address">地址:</label>
                <input type="text" name="address" id="address" value="${sysUser.address }">
            </div>
            <div>
                <label>角色:</label>
                <!-- 列出所有的角色分类 -->
                <input type="hidden" value="${sysUser.roleId }" id="rid"/>
                <%--<select name="role" id="roleList"></select>--%>
                <select name="roleId" id="roleId">
                    <c:choose>
                        <c:when test="${sysUser.roleId == 1 }">
                            <option value="1" selected="selected">系统管理员</option>
                            <option value="2">店长</option>
                            <option value="3">普通用户</option>
                        </c:when>
                        <c:when test="${sysUser.roleId == 2 }">
                            <option value="1">系统管理员</option>
                            <option value="2" selected="selected">店长</option>
                            <option value="3">普通用户</option>
                        </c:when>
                        <c:otherwise>
                            <option value="1">系统管理员</option>
                            <option value="2">店长</option>
                            <option value="3" selected="selected">普通用户</option>
                        </c:otherwise>
                    </c:choose>
                </select>
                <font color="red"></font>
            </div>
            <div class="supplierAddBtn">
                <input type="submit" name="save" id="save" value="保存"/>
                <input type="button" id="back" name="back" value="返回"/>
            </div>
        </form>
    </div>
    
    <%@include file="/WEB-INF/jsp/common/foot.jsp" %>

3.改造Controller层:SysUserController中新增修改用户接口

 /**
  * 修改用户信息
  * @param sysUser
  * @param session
  * @return
  */
 @PostMapping("/update")
 public String update(SysUser sysUser, HttpSession session) {
     sysUser.setUpdatedUserId(((SysUser) session.getAttribute(Constants.USER_SESSION)).getId());
     if (userService.modifyUser(sysUser)) {
         return "redirect:/user/list";
     }
     return "sysUser/update";
 }

4.Spring表单标签

4.1Spring表单标签-引用标签库
  • Spring提供的一套表单标签库

  • 将模型数据中的表单对象绑定到HTML表单元素中

  • 用法

    • 必须在JSP页面中添加引用Spring标签库的声明

      <%@ taglib prefix="fm" uri="http://www.springframework.org/tags/form"%>
      
    • 引入声明之后即可使用Spring表单标签

4.2Spring表单标签-常用表单标签

Spring常用表单标签

名称说明
fm:form/渲染表单元素
fm:input/输入框组件标签
fm:password/密码框组件标签
fm:hidden/隐藏框组件标签
fm:textarea/多行输入框组件标签
fm:radiobutton/单选框组件标签
fm:checkbox/复选框组件标签
fm:select/下拉列表组件标签
fm:error/显示表单数据校验对应的错误信息
4.3Spring表单标签-fm:form常用属性

<fm:form>标签

  1. modelAttribute

    • 指定绑定的模型属性
    • 若不指定该属性,默认从模型中尝试获取名为"command"的表单属性,建议指定该属性
  2. action

    • 指定表单提交的目标URL
    • 可不指定,则自动以获取表单页面的URL为目标进行提交,可以通过不同请求方式区分不同操作
  3. method

    • GET
    • POST
4.4Spring表单标签-标签属性

标签属性

属性描述
path属性路径,表示表单对象属性,如account、realName等
cssClass表单组件对应的CSS样式类名
cssErrorClass当提交表单后报错(服务端错误),采用的CSS样式类
cssStyle表单组件对应的CSS样式
htmlEscape绑定的表单属性值是否要对HTML特殊字符进行转换,默认为true
4.5演示示例

使用Spring表单标签实现新增用户信息

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="fm" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script type="text/javascript" src="${pageContext.request.contextPath }/statics/calendar/WdatePicker.js"></script>
<title>新增用户</title>
</head>
<body>
<fm:form method="post" modelAttribute="sysUser" >
	用户编码:<fm:input path="account"/><br/>
	用户名称:<fm:input path="realName"/><br/>
	用户密码:<fm:password path="password"/><br/>
	用户生日:<fm:input path="birthday" Class="Wdate" readonly="readonly" onclick="WdatePicker();" class="Wdate"/><br/>
	用户地址:<fm:input path="address"/><br/>
	联系电话:<fm:input path="phone"/><br/>
	用户角色:
	<fm:radiobutton path="roleId" value="1"/>系统管理员
	<fm:radiobutton path="roleId" value="2"/>经理
	<fm:radiobutton path="roleId" value="3" checked="checked"/>普通用户
	<br/>
	<input type="submit" value="保存"/>
</fm:form>

</body>
</html>


/**
 * 跳转到添加用户页面
 * @return
 */
@GetMapping("/toAdd")
public String addUser(){
	return "sysUser/add";
}
/**
 * 添加用户
 * @param sysUser
 * @param session
 * @return
 */
@PostMapping("/add")
public String addUserSave(SysUser sysUser ,HttpSession session){
	sysUser.setCreatedUserId(((SysUser)session.getAttribute(Constants.USER_SESSION)).getId());
	if(sysUserService.add(sysUser)){
		return "redirect:/user/list";
	}
	return "sysUser/add";
}

5.数据校验

5.1数据校验-JSR 303简介

服务器端的数据校验

  • 利用Spring自带的验证框架
  • 利用JSR 303实现

JSR 303

  1. Java为Bean数据合法性校验所提供的标准框架
  2. Spring MVC支持JSR 303标准的校验框架
  3. JSR 303通过在Bean属性上标注类似于@NotNull@Max等标准的注解指定校验规则,并通过标准的验证接口对Bean进行验证

注意:

  • Spring本身没有提供JSR 303的实现,是由Hibernate Validator实现的,所以需要在项目中加入来自Hibernate Validator库的jar文件
5.2数据校验-JSR 303约束

JSR 303 约束

约束说明
@Null被注释的元素必须为null
@NotNull被注释的元素必须不为null
@AssertTrue被注释的元素必须为true
@AssertFalse被注释的元素必须为false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min)被注释的元素的大小必须在指定的范围内
@Digits(integer,fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式
5.3数据校验-实现步骤分析

需求说明

  • 在前面演示案例的基础上,添加JSR 303验证

实现步骤

1. 将jar包引入到项目中

  • hibernate-validator-6.1.2.Final.jar

2. 修改SysUser.java

  • 为需要进行验证的属性添加相应的校验注解

3.修改SysUserController.java

  • 在控制层开启数据校验功能
  • 处理方法add()的入参
  • 标注@Valid注解
  • BindingResult参数

4.修改add.jsp

  • 通过<fm:errors/>标签将错误信息显示在JSP页面的指定位置
5.4演示示例

演示示例—使用JSR303框架完成新增用户的数据校验

  1. maven中添加依赖

    org.hibernate.validator hibernate-validator 6.2.1.Final
  2. 为SysUser实体类添加属性

    package com.aiden.springmvc.cvs.pojo;

    import java.util.Date;
    import javax.validation.constraints.NotEmpty;
    import javax.validation.constraints.NotNull;
    import javax.validation.constraints.Past;
    import org.hibernate.validator.constraints.Length;
    import org.springframework.format.annotation.DateTimeFormat;

    public class SysUser {
    private Integer id; //id
    @NotEmpty(message=“用户编码不能为空”)
    private String account; //用户编码
    @NotEmpty(message=“用户名称不能为空”)
    private String realName; //用户名称
    @NotNull(message=“密码不能为空”)
    @Length(min=6,max=10,message=“用户密码长度为6-10”)
    private String password; //用户密码
    private Integer sex; //性别
    @Past(message=“必须是一个过去的时间”)
    @DateTimeFormat(pattern=“yyyy-MM-dd”)
    private Date birthday; //出生日期
    //…
    }

  3. Controller 控制器

    /**

    • 跳转到添加用户页面
    • @param sysUser
    • @return
      /
      @GetMapping(“/add”)
      public String toAdd(@ModelAttribute(“sysUser”) SysUser sysUser){
      return “sysUser/add”;
      }
      /
      *
    • 添加用户
    • @param sysUser
    • @param session
    • @return
      */
      @PostMapping(“/add”)
      public String add(@Valid SysUser sysUser, BindingResult bindingResult , HttpSession session){
      if(bindingResult.hasErrors()){
      logger.debug(“添加用户验证失败”);
      return “sysUser/add”;
      }
      sysUser.setCreatedUserId(((SysUser)session.getAttribute(Constants.USER_SESSION)).getId());
      if(sysUserService.add(sysUser)){
      return “redirect:/user/list”;
      }
      return “sysUser/add”;
      }
  4. View视图页面

    <%@ page language=“java” contentType=“text/html; charset=UTF-8”
    pageEncoding=“UTF-8”%>
    <%@ taglib prefix=“fm” uri=“http://www.springframework.org/tags/form” %>

    Insert title here
    用户编码:

    用户名称:

    用户密码:

    用户生日:
    用户地址:
    联系电话:
    用户角色: 系统管理员 经理 普通用户

6.文件上传

6.1Spring MVC文件上传

Spring MVC-文件上传

  1. MultipartResolver接口

    1. 提供了对文件上传功能的直接支持,可以将上传请求包装成可以直接获取的文件数据

      1. 实现类
    • StandardServletMultipartResolver
    • CommonsMultipartResolver
    • 使用Apache Commons FileUpload组件完成单文件上传操作
6.2单文件上传-需求说明

需求说明

  • 改造724系统-新增用户信息时,需上传用户的证件照(非必填项)
  • 使用CommonsMultipartResolver类完成单文件上传操作

在这里插入图片描述

6.3单文件上传-实现步骤

实现步骤

  1. 导入依赖jar包

    • commons-io-2.4.jar
    • commons-fileupload-1.2.2.jar
  2. 配置MultipartResolver解析器

    • CommonsMultipartResolver






  3. 增加字段

    • 在用户表t_sys_user中增加证件照字段(idPicPath),用以存放文件路径
    • 在SysUser类增加相应的属性(idPicPath)
    • 对用户模块SysUserDaoImpl类的add()方法进行改造
  4. 改造Controller层

    • 对SysUserController中的add()接口进行改造,处理文件上传的请求方式一定是POST请求,GET请求无法处理文件上传。
  5. 改造View层

    1. 在保存用户信息的form表单中添加上传文件的相关代码
    2. enctype=“multipart/form-data”:指定表单内容类型,支持文件上传
    3. <input type="file" name="idPic" id="idPic"/>:用来上传文件的file组件
6.4单文件上传-MultipartFile

MultipartFile

  • 可以接受上传的文件数据,并提供了获取上传文件内容、文件名、文件存储等功能,是处理文件上传工作的核心工具
  • 提供了很多处理上传文件的重要方法

在这里插入图片描述

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

原因

  1. 乱码问题:原文件名存在中文
  2. 覆盖问题:原文件名与服务器上已有文件重名
  3. 重新定义上传文件名(保证不重名)
  4. 当前系统时间+随机数+“_Personal.”+prefix

File.separator

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

新增用户信息-单文件上传

  1. 添加maven依赖

    commons-io commons-io 2.4 commons-fileupload commons-fileupload 1.2.2
  2. 配置MultipartResolver解析器

  3. 增加字段

    private String idPicPath; //证件照路径
    public String getIdPicPath() {
    return idPicPath;
    }
    public void setIdPicPath(String idPicPath) {
    this.idPicPath = idPicPath;
    }

  4. 改造Controller层

    private Logger logger = Logger.getLogger(SysUserController.class);
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysRoleService sysRoleService;
    /**

    • 跳转到添加用户页面
    • @return
      /
      @GetMapping(“/toAdd”)
      public String toAdd(){
      return “sysUser/add”;
      }
      /
      *
    • 添加用户
    • @param sysUser
    • @param session
    • @return
      */
      @PostMapping(“/add”)
      public String add(SysUser sysUser,HttpSession session,HttpServletRequest request,
      @RequestParam(value =“idPic”, required = false) MultipartFile idPic){
      String idPicPath = null;
      //判断文件是否为空
      if(!idPic.isEmpty()){
      String path = request.getSession().getServletContext().getRealPath(“statics”+ File.separator+“uploadfiles”);
      logger.info(“上传文件路径”+path);
      String originalFile = idPic.getOriginalFilename();//原文件名
      logger.info(“源文件名为:”+originalFile);
      String prefix= FilenameUtils.getExtension(originalFile);//原文件后缀
      logger.debug(“原文件后缀为:” + prefix);
      int filesize = 500000;
      logger.debug(“文件大小:” + idPic.getSize());
      if(idPic.getSize() > filesize){//上传大小不得超过 500k
      request.setAttribute(“uploadFileError”, " * 上传大小不得超过 500k");
      return “sysUser/add”;
      }else if(prefix.equalsIgnoreCase(“jpg”) || prefix.equalsIgnoreCase(“png”)
      || prefix.equalsIgnoreCase(“jpeg”) || prefix.equalsIgnoreCase(“pneg”)){//上传图片格式不正确
      String fileName = System.currentTimeMillis()+ RandomUtils.nextInt(1000000)+“_Personal.” + prefix;
      logger.debug(“新生成的文件名称为:” + idPic.getName());
      File targetFile = new File(path);
      //创建文件目录
      if(!targetFile.exists()){
      targetFile.mkdirs();
      }
      //保存
      try {
      idPic.transferTo(new File(targetFile, fileName));
      } catch (Exception e) {
      e.printStackTrace();
      request.setAttribute(“uploadFileError”, " * 上传失败!“);
      return “sysUser/add”;
      }
      idPicPath = File.separator+“statics”+ File.separator+“uploadfiles” + File.separator+fileName;
      }else{
      request.setAttribute(“uploadFileError”, " * 上传图片格式不正确”);
      return “sysUser/add”;
      }
      }
      sysUser.setCreatedUserId(((SysUser)session.getAttribute(Constants.USER_SESSION)).getId());
      sysUser.setIdPicPath(idPicPath);
      if(sysUserService.add(sysUser)){
      return “redirect:/user/list”;
      }
      return “sysUser/add”;
      }
  5. 改造View层

    <%@ page language=“java” contentType=“text/html; charset=UTF-8”
    pageEncoding=“UTF-8”%>
    <%@include file=“/WEB-INF/jsp/common/head.jsp” %>

    当前位置: 用户管理页面 >> 用户添加页面
    女 男
    <%----%> 系统管理员 店长 普通用户
    <%@include file="/WEB-INF/jsp/common/foot.jsp" %>

7.多文件上传

7.1多文件上传 -需求说明

需求说明

  • 改造724系统-新增用户信息时,需上传用户的证件照和工作证照片(非必填项)
  • 使用CommonsMultipartResolver类完成单文件上传操作

在这里插入图片描述

7.2多文件上传-实现步骤

实现步骤

  1. 增加字段
    • 在用户表t_sys_user中增加证件照字段(idPicPath)和工作证字段(workPicPath)
    • 在SysUser类增加证件照属性(idPicPath)和工作证属性(workPicPath)
    • 对用户模块SysUserDaoImpl类的add()方法进行升级改造
  2. 改造Controller层
    • 对SysUserController中的add()接口进行改造
      • 修改入参MultipartFile为数组
      • 如果使用MultipartFile数组实现多文件上传工作,需要在该参数前面加上@RequestParam注解;否则会报错
  3. 改造View层
    • 在保存用户信息的form表单中添加上传工作证照片的相关代码
7.3演示示例

新增用户信息-多文件上传

  1. 增加字段

    private String idPicPath; //证件照路径
    private String workPicPath; //工作证照片路径
    public String getIdPicPath() {
    return idPicPath;
    }
    public void setIdPicPath(String idPicPath) {
    this.idPicPath = idPicPath;
    }
    public String getWorkPicPath() {
    return workPicPath;
    }
    public void setWorkPicPath(String workPicPath) {
    this.workPicPath = workPicPath;
    }

  2. SysUserDaoImpl类的add()方法进行升级改造

    @Override
    public int add(Connection connection, SysUser user) throws Exception {
    // TODO Auto-generated method stub
    PreparedStatement pstm = null;
    int updateRows = 0;
    if(null != connection){
    String sql = “insert into t_sys_user (account,realName,password” +
    “, roleId,sex,birthday,phone,address,createdTime” +
    ", createdUserId,idPicPath,workPicPath) " +
    “values(?,?,?,?,?,?,?,?,?,?,?,?)”;
    Object[] params = {user.getAccount(),user.getRealName()
    ,user.getPassword(),user.getRoleId(),user.getSex()
    ,user.getBirthday(),user.getPhone(),user.getAddress()
    ,user.getCreatedTime(),user.getCreatedUserId()
    ,user.getIdPicPath(),user.getWorkPicPath()};
    updateRows = BaseDao.execute(connection, pstm, sql, params);
    BaseDao.closeResource(null, pstm, null);
    }
    return updateRows;
    }

  3. 改造Controller层

    package com.aiden.springmvc.cvs.controller;

    import com.aiden.springmvc.cvs.pojo.SysRole;
    import com.aiden.springmvc.cvspojo.SysUser;
    import com.aiden.springmvc.cvs.service.SysRoleService;
    import com.aiden.springmvc.cvs.service.SysUserService;
    import com.aiden.springmvc.cvs.utils.Constants;
    import com.aiden.springmvc.cvs.utils.PageSupport;
    import org.apache.commons.io.FilenameUtils;
    import org.apache.commons.lang.math.RandomUtils;
    import org.apache.log4j.Logger;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;

    import javax.annotation.Resource;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpSession;
    import java.io.File;
    import java.util.Date;
    import java.util.List;

    @Controller
    @RequestMapping(“/user”)
    public class SysUserController {
    private Logger logger = Logger.getLogger(SysUserController.class);
    @RequestMapping(“/hello”)
    public String welcome(String realName){
    logger.info(“欢迎使用Spring MVC, realName:” + realName);
    return “index”;
    }
    @Resource
    private SysUserService sysUserService;
    @Resource
    private SysRoleService sysRoleService;

    /**

    • 跳转到添加用户页面
    • @return
      */
      @GetMapping(“/toAdd”)
      public String addUser(){
      return “sysUser/add”;
      }

    /**

    • 添加用户
    • @param sysUser
    • @param session
    • @return
      /
      /
      @PostMapping(“/add”)
      public String add(SysUser sysUser,HttpSession session,HttpServletRequest request,
      @RequestParam(value =“idPic”, required = false) MultipartFile idPic){
      String idPicPath = null;
      //判断文件是否为空
      if(!idPic.isEmpty()){
      String path = request.getSession().getServletContext().getRealPath(“statics”+ File.separator+“uploadfiles”);
      logger.info(“上传文件路径”+path);
      String originalFile = idPic.getOriginalFilename();//原文件名
      logger.info(“源文件名为:”+originalFile);
      String prefix= FilenameUtils.getExtension(originalFile);//原文件后缀
      logger.debug(“原文件后缀为:” + prefix);
      int filesize = 500000;
      logger.debug(“文件大小:” + idPic.getSize());
      if(idPic.getSize() > filesize){//上传大小不得超过 500k
      request.setAttribute(“uploadFileError”, " * 上传大小不得超过 500k");
      return “sysUser/add”;
      }else if(prefix.equalsIgnoreCase(“jpg”) || prefix.equalsIgnoreCase(“png”)
      || prefix.equalsIgnoreCase(“jpeg”) || prefix.equalsIgnoreCase(“pneg”)){//上传图片格式不正确
      String fileName = System.currentTimeMillis()+ RandomUtils.nextInt(1000000)+“_Personal.” + prefix;
      logger.debug(“新生成的文件名称为:” + idPic.getName());
      File targetFile = new File(path);
      if(!targetFile.exists()){
      targetFile.mkdirs();
      }
      //保存
      try {
      idPic.transferTo(new File(targetFile, fileName));
      } catch (Exception e) {
      e.printStackTrace();
      request.setAttribute(“uploadFileError”, " * 上传失败!“);
      return “sysUser/add”;
      }
      idPicPath = File.separator+“statics”+ File.separator+“uploadfiles” + File.separator+fileName;
      }else{
      request.setAttribute(“uploadFileError”, " * 上传图片格式不正确”);
      return “sysUser/add”;
      }
      }
      sysUser.setCreatedUserId(((SysUser)session.getAttribute(Constants.USER_SESSION)).getId());
      sysUser.setIdPicPath(idPicPath);
      if(sysUserService.add(sysUser)){
      return “redirect:/user/list”;
      }
      return “sysUser/add”;
      }*/

    /**

    • 多文件上传

    • @param sysUser

    • @param session

    • @param request

    • @param attachs

    • @return
      */
      @PostMapping(value=“/add”)
      public String add(SysUser sysUser,HttpSession session,HttpServletRequest request,
      @RequestParam(value =“attachs”, required = false) MultipartFile[] attachs){
      String idPicPath = null;
      String workPicPath = null;
      String errorInfo = null;
      boolean flag = true;
      String path = request.getSession().getServletContext().getRealPath(“statics”+File.separator+“uploadfiles”);
      logger.info("uploadFile path ============== > "+path);
      for(int i = 0;i < attachs.length ;i++){
      MultipartFile attach = attachs[i];
      if(!attach.isEmpty()){
      if(i == 0){
      errorInfo = “uploadFileError”;
      }else if(i == 1){
      errorInfo = “uploadWpError”;
      }
      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(errorInfo, " * 上传大小不得超过 500k”);
      flag = false;
      }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);
      if(!targetFile.exists()){
      targetFile.mkdirs();
      }
      //保存
      try {
      attach.transferTo(new File(targetFile, fileName));
      } catch (Exception e) {
      e.printStackTrace();
      request.setAttribute(errorInfo, " * 上传失败!”);
      flag = false;
      }
      if(i == 0){
      idPicPath = File.separator+“statics”+ File.separator
      +“uploadfiles”+File.separator+fileName;
      }else if(i == 1){
      workPicPath = File.separator+“statics”+ File.separator
      +“uploadfiles”+File.separator+fileName;
      }
      logger.debug("idPicPath: " + idPicPath);
      logger.debug("workPicPath: " + workPicPath);

       	}else{
       		request.setAttribute(errorInfo, " * 上传图片格式不正确");
       		flag = false;
       	}
       }
      

      }
      if(flag){
      sysUser.setCreatedUserId(((SysUser)session.getAttribute(Constants.USER_SESSION)).getId());
      sysUser.setIdPicPath(idPicPath);
      sysUser.setWorkPicPath(workPicPath);
      if(sysUserService.add(sysUser)){
      return “redirect:/user/list”;
      }
      }
      return “sysUser/add”;
      }
      }

  4. 改造View层

    <%@ page language=“java” contentType=“text/html; charset=UTF-8”
    pageEncoding=“UTF-8”%>
    <%@include file=“/WEB-INF/jsp/common/head.jsp” %>

    当前位置: 用户管理页面 >> 用户添加页面
    女 男
    <%----%> 系统管理员 店长 普通用户
    <%--
    --%>
    <%@include file="/WEB-INF/jsp/common/foot.jsp" %>

8.本章总结

8.1导图梳理

在这里插入图片描述

;