字段自动填充
一、首先我们需要在表上创建相应的字段
1:值得注意的是这个类型,datetime,还有别的操作时间的类型,这个区别还是有一点,详细可以百度一下,此处就不写了
二、标准的java实体映射类肯定是需要的
1:这第一个注解:@DateTimeFormat,就是指定这个时间格式,这个与上述的datetime还是有一点关系的,可以自己百度,尝试一下别的
@DateTimeFormat只能用在**【表单键值对】**这种提交方式,而且只能格式化前端->后端数据,不能用于json格式的提交方式,也不能用于后端->前端的格式化
@JsonFormat只能用在**【json格式】**这种提交方式,而且既能格式化前端-后端的数据,也能格式化后端->前端的数据
重点:当前端传来json串,后台用@ReuqestBody接收,必须用@JsonFormat 规定接收的时间格式。上面直接这么使用,在我们中国来讲和我们的北京时间,会相差8个小时,因为我们是东八区(北京时间)。
所以我们在格式化的时候要指定时区(timezone )
public class Param {
@JsonFormat(shape = JsonFormat.Shape.STRING , pattern = "yyyy-MM-dd HH:mm:ss", , timezone = "Asia/Shanghai")
private Date date;
}
2:关键是第二个注解:@TableField,相当于表达这是什么操作,然后与下文形成对应
3:注意:!!!! 此处的Date 是java.util.Date,不要导sql的包,sql也有一个Date,具体我也没研究为啥,如果导了这个sql包,会报错
三、注解有了还不行,还要做最后一步,实现MetaObjectHandler接口
package com.cy.pj.common.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.cy.pj.common.api.ShiroUtils;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 配置字段自动填充
* 自定义MyMetaObjectHandler 字段自动填充处理类实现 MetaObjectHandler
*/
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
/**
* fieldName:实体映射类的属性名
* 第二个参数为值
* 第三个参数:元数据对象
* @param metaObject
*/
//新增时填充
@Override
public void insertFill(MetaObject metaObject) {
//按名称设置字段值
this.setFieldValByName("createdTime", new Date(), metaObject); //创建时间
this.setFieldValByName("modifiedTime", new Date(), metaObject); //修改时间
this.setFieldValByName("createdUser", ShiroUtils.getUsername(), metaObject); //创建人
this.setFieldValByName("modifiedUser", ShiroUtils.getUsername(), metaObject); //修改人
}
//修改时填充
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("modifiedTime", new Date(), metaObject); //修改时间
this.setFieldValByName("modifiedUser", ShiroUtils.getUsername(), metaObject); //修改人
}
}
1:此处需要注意,需要交给spring容器管理
2:实现这个接口的两个方法,insertFill和updateFill
3:测试即可实现自动填充,当然,既然是自动填充,所以我们不需要传值
四、如果出现时间点不一样的情况,一般是差8个小时[东八区],那么这个时候,我们就需要添加一点配置
复制代码
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
#关键操作,数据库名后面添加:?
serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=UTF-8
url: jdbc:mysql://192.168.27.212:3306/mydata?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=UTF-8
jackson:
#时间的格式
date-format: yyyy-MM-dd HH:mm:ss
#时间+8小时
time-zone: GMT+8
复制代码
五、如果测试还是不行,配置文件不起作用,那就只能写死时间,使用时间的工具类【此操作可能导致多台设备添加的时间不一致,谨慎使用】
1、引入依赖
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
2、在实现MetaObjectHandler接口的类中,要把new Date();改掉
1 @Component
2 public class MyObjectHandler implements MetaObjectHandler {
3 @Override
4 public void insertFill(MetaObject metaObject) {
5 /**
6 * fieldName:实体映射类的属性名
7 * 第二个参数:属性值
8 * 第三个:元数据对象
9 * DateTime.now().plusHours(13).toDate():时间+13小时,
10 * 这个13小时只是我这里差的值,差多少改多少
11 */
12 this.setFieldValByName("createTime", DateTime.now().plusHours(13).toDate(),metaObject);
13 this.setFieldValByName("updateTime",DateTime.now().plusHours(13).toDate(),metaObject);
14 }
15
16 @Override
17 public void updateFill(MetaObject metaObject) {
18 this.setFieldValByName("updateTime",DateTime.now().plusHours(13).toDate(),metaObject);
}
}
六、以上的写死时间的操作,纯属个人娱乐操作,没有实际应用意义,只有配置文件生效的那个操作,才是最好的操作,传值的时候,什么都不需要写,对象传值的话,直接忽略它就好
=====================================================
图片上传
1.准备ImageVO对象
package com.jt.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@NoArgsConstructor
@AllArgsConstructor
public class ImageVO {
//{"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
private Integer error; //错误信息 0程序运行正常 1.文件上传有误.
private String url; //图片访问的虚拟路径
private Integer width; // >0
private Integer height; // >0
//设定上传失败的方法
public static ImageVO fail(){
return new ImageVO(1,null,null,null);
}
public static ImageVO success(String url,Integer width,Integer height){
return new ImageVO(0,url,width,height);
}
}
2.编辑FileController
通过MultipartFile(多部分文件)获取上传的文件
/**
* 实现文件上传
* url地址: http://localhost:8091/pic/upload?dir=image
* 参数: uploadFile: 文件的字节信息.
* 返回值: {"error":0,"url":"图片的保存路径","width":图片的宽度,"height":图片的高度}
* ImageVO对象...
*/
@RequestMapping("/pic/upload")
public ImageVO upload(MultipartFile uploadFile){
return fileService.upload(uploadFile);
}
3.编辑FileServiceImpl (上传地址写死了,图片url为虚假路径,后面优化)
图像数据读写利器 -- ImageIO (处理图像的API)
package com.jt.service;
import com.jt.vo.ImageVO;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Service
public class FileServiceImpl implements FileService{
private String rootDirPath = "D:/JT-SOFT/images";
//1.2 准备图片的集合 包含了所有的图片类型.
private static Set<String> imageTypeSet;
static {
imageTypeSet = new HashSet<>();
imageTypeSet.add(".jpg");
imageTypeSet.add(".png");
imageTypeSet.add(".gif");
}
/**
* 完善的校验的过程
* 1. 校验是否为图片
* 2. 校验是否为恶意程序
* 3. 防止文件数量太多,分目录存储.
* 4. 防止文件重名
* 5. 实现文件上传.
* @param uploadFile
* @return
*/
@Override
public ImageVO upload(MultipartFile uploadFile) {
//1.校验图片类型 jpg|png|gif..JPG|PNG....
//1.1 获取当前图片的名称 之后截取其中的类型. abc.jpg
String fileName = uploadFile.getOriginalFilename();
int index = fileName.lastIndexOf(".");
String fileType = fileName.substring(index);
//将数据转化为小写
fileType = fileType.toLowerCase();
//1.3 判断图片类型是否正确.
if(!imageTypeSet.contains(fileType)){
//图片类型不匹配
return ImageVO.fail();
}
//2.校验是否为恶意程序 根据宽度/高度进行判断
try {
//2.1 利用工具API对象 读取字节信息.获取图片对象类型
BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
//2.2 校验是否有宽度和高度
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if(width==0 || height==0){
return ImageVO.fail();
}
//3.分目录存储 yyyy/MM/dd 分隔
//3.1 将时间按照指定的格式要求 转化为字符串.
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
.format(new Date());
//3.2 拼接文件存储的目录对象
String fileDirPath = rootDirPath + dateDir;
File dirFile = new File(fileDirPath);
//3.3 动态创建目录
if(!dirFile.exists()){
dirFile.mkdirs();
}
//4.防止文件重名 uuid.jpg 动态拼接
//4.1 动态生成uuid 实现文件名称拼接 名.后缀
String uuid =
UUID.randomUUID().toString().replace("-", "");
String realFileName = uuid + fileType;
//5 实现文件上传
//5.1 拼接文件真实路径 dir/文件名称.
String realFilePath = fileDirPath + realFileName;
//5.2 封装对象 实现上传
File realFile = new File(realFilePath);
uploadFile.transferTo(realFile);
//实现文件上传成功!!!!
String url = "https://img14.360buyimg.com/n0/jfs/t1/45882/22/7027/53284/5d49358aE9c25c1bd/fb7365463f6a1a7b.jpg";
return ImageVO.success(url,width,height);
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
}
}
4. 文件上传优化
1.1 url优化
说明: 如果需要通过网络虚拟路径访问服务器.则应该按照如下的配置实现.
1.本地磁盘路径: D:\JT-SOFT\images\2020\09\30\a.jpg
2.网络虚拟路径: http://image.jt.com\2020\09\30\a.jpg
1.2 编辑pro配置文件
1.3 完成属性的动态赋值
package com.jt.service;
import com.jt.vo.ImageVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Service
@PropertySource("classpath:/properties/images.properties") //容器动态加载指定的配置文件
public class FileServiceImpl implements FileService{
//由于属性的值后期可能会发生变化,所以应该动态的获取属性数据. 利用pro配置文件
@Value("${image.rootDirPath}")
private String rootDirPath; // = "D:/JT-SOFT/images";
@Value("${image.urlPath}")
private String urlPath; // = "http://image.jt.com";
//1.2 准备图片的集合 包含了所有的图片类型.
private static Set<String> imageTypeSet;
static {
imageTypeSet = new HashSet<>();
imageTypeSet.add(".jpg");
imageTypeSet.add(".png");
imageTypeSet.add(".gif");
}
/**
* 完善的校验的过程
* 1. 校验是否为图片
* 2. 校验是否为恶意程序
* 3. 防止文件数量太多,分目录存储.
* 4. 防止文件重名
* 5. 实现文件上传.
* @param uploadFile
* @return
*/
@Override
public ImageVO upload(MultipartFile uploadFile) {
//0.防止有多余的空格 所以先做去空格的处理
rootDirPath.trim();
urlPath.trim();
//1.校验图片类型 jpg|png|gif..JPG|PNG....
//1.1 获取当前图片的名称 之后截取其中的类型. abc.jpg
String fileName = uploadFile.getOriginalFilename();
int index = fileName.lastIndexOf(".");
String fileType = fileName.substring(index);
//将数据转化为小写
fileType = fileType.toLowerCase();
//1.3 判断图片类型是否正确.
if(!imageTypeSet.contains(fileType)){
//图片类型不匹配
return ImageVO.fail();
}
//2.校验是否为恶意程序 根据宽度/高度进行判断
try {
//2.1 利用工具API对象 读取字节信息.获取图片对象类型
BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
//2.2 校验是否有宽度和高度
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
if(width==0 || height==0){
return ImageVO.fail();
}
//3.分目录存储 yyyy/MM/dd 分隔
//3.1 将时间按照指定的格式要求 转化为字符串.
String dateDir = new SimpleDateFormat("/yyyy/MM/dd/")
.format(new Date());
//3.2 拼接文件存储的目录对象
String fileDirPath = rootDirPath + dateDir;
File dirFile = new File(fileDirPath);
//3.3 动态创建目录
if(!dirFile.exists()){
dirFile.mkdirs();
}
//4.防止文件重名 uuid.jpg 动态拼接
//4.1 动态生成uuid 实现文件名称拼接 名.后缀
String uuid =
UUID.randomUUID().toString().replace("-", "");
String realFileName = uuid + fileType;
//5 实现文件上传
//5.1 拼接文件真实路径 dir/文件名称.
String realFilePath = fileDirPath + realFileName;
//5.2 封装对象 实现上传
File realFile = new File(realFilePath);
uploadFile.transferTo(realFile);
//实现文件上传成功!!! http://image.jt.com\2020\09\30\a.jpg
String url = urlPath + dateDir + realFileName;
return ImageVO.success(url,width,height);
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
}
}
5.MultipartFile接口常用方法详解
说明:这个类一般是用来接收前台传过来的文件;
MultipartFile是spring类型,代表HTML中form data方式上传的文件,包含二进制数据+文件名称。
<body>
<h1>实现文件上传</h1>
<!--enctype="开启多媒体标签" 定义为上传文件 -->
<form action="http://localhost:8091/file" method="post"
enctype="multipart/form-data">
<input name="fileImage" type="file" />
<input type="submit" value="上传"/>
</form>
</body>
概述: MultipartFile为org.springframework.web.mutipart包下的一个类,也就是说如果想使用MultipartFile这个类就必须引入spring框架,换句话说,如果想在项目中使用MultipartFile这个类,那么项目必须要使用spring框架才可以,否则无法引入这个类。MultipartFile翻译成中文来讲就是“多组件的文档”,不用太在乎他的中文含义,一般来讲使用MultipartFile这个类主要是来实现以表单的形式进行文件上传功能。
常用方法:
(1)、getName方法
getName方法获取的是前后端约定的传入文件的参数的名称,在SpringBoot后台中则是通过@Param("uploadFile") 注解定义的内容
(2)、getOriginalFileName方法
getOriginalFileName方法获取的是文件的完整名称,包括文件名称+文件拓展名。
(3)、getContentType方法
getContentType方法获取的是文件的类型,注意是文件的类型,不是文件的拓展名。
(4)、isEmpty方法
isEmpty方法用来判断传入的文件是否为空,如果为空则表示没有传入任何文件。
(5)、getSize方法
getSize方法用来获取文件的大小,单位是字节。
(6)、getBytes方法
getBytes方法用来将文件转换成一种字节数组的方式进行传输,会抛出IOException异常。
(7)、getInputStream方法
getInputStream方法用来将文件转换成输入流的形式来传输文件,会抛出IOException异常。
(8)、transferTo方法
transferTo方法用来将接收文件传输到给定目标路径,会抛出IOException、IllegalStateException异常。该方法在实际项目开发中使用较少。