1.1引入图片处理jar包
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>
1.2.Thumbnailator图片处理
要加水印的图片位置:E:/JAVA/JAVA1/javaEE/xiaoyuanshangpu/xiaohuangren.jpg
水印图片的位置要在:src/main/resources下,这样便于访问到,如果不放在对应java的resources下,不能访问到。
ImageUtil.java
public class ImageUtil {
public static void main(String[] args) throws IOException {
//获取Classpath的路径
String basePath = Thread.currentThread()
.getContextClassLoader()
.getResource("").getPath();
System.out.println(basePath);
//要处理的图片
Thumbnails.of(new File("E:/JAVA/JAVA1/javaEE/xiaoyuanshangpu/xiaohuangren.jpg"))
//输出图片的长和宽
.size(800,600)
//给图片添加水印,三个参数
.watermark( //水印位置
Positions.BOTTOM_RIGHT,
//水印图片的路径
ImageIO.read(new File(basePath+"watermark.jpg")),
//水印透明度
0.75f)
//压缩80%
.outputQuality(0.8f)
//输出添加水印后图片的位置
.toFile("E:/JAVA/JAVA1/javaEE/xiaoyuanshangpu/xiaohuangrennew.jpg");
}
}
结果展示:在E:/JAVA/JAVA1/javaEE/xiaoyuanshangpu/文件夹下
注意:最好把路径都设为英文名称,如果项目名称为中文名称,水印图片无法读取
PathUtil.java
package com.imooc.o2o.util;
public class PathUtil {
//本系统的分隔符
private static String seperator=System.getProperty("file.separator");
//根据不同的操作系统,设置储存图片文件不同的根目录(根路径),不带图片的名称xxx.jpg
public static String getImgBasePath(){
String os=System.getProperty("os.name");
String basePath="";
if (os.toLowerCase().startsWith("win")){
basePath="E:/JAVA/JAVA1/javaEE/xiaoyuanshangpu/image";//根据自己的实际路径进行设置根目录
}else {
basePath = "/home/o2o/image";//根据自己的实际路径进行设置
}
//linux为/,windows为\,通过代替语法将本系统分隔符代替
basePath=basePath.replace("/",seperator);
return basePath;
}
//根据shopId返回项目图片相对路径(子路径),不带图片的名称xxx.jpg
public static String getShopImagePath(long shopId){
String imagePath = "/upload/item/shop/"+ shopId + "/";//自动生成此路径
return imagePath.replace("/",seperator);
}
}
完善ImageUtil.java
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class ImageUtil {
//classpath路径
private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
private static final Random r = new Random();
/**
* 处理缩略图,并返回新生成图片的相对值路径
* @param thumbnail 用户上传的文件
* @param targetAddr 新的文件存储在targetAddr目录中
* @return 返回门面照和小图
*/
public static String generateThumbnail(File thumbnail,String targetAddr) {
//获取文件的随机名称
String realFileName = getRandomFileName();
//获取用户上传的文件的扩展名称(文件后缀)
String extension = getFileExtension(thumbnail);
//创建图片的存储目录(这个目录包括根目录加上相对目录)
makeDirPath(targetAddr);
//图片的目录
String relativeAddr = targetAddr +realFileName + extension;
File dest = new File(PathUtil.getImgBasePath() + relativeAddr);
try {
Thumbnails.of(thumbnail).size(200, 200)
.watermark(Positions.BOTTOM_RIGHT,ImageIO.read(new File(basePath + "watermark.jpg")),0.25f)
.outputQuality(0.8f).toFile(dest);
}catch (IOException e) {
e.printStackTrace();
}
return relativeAddr;
}
/**
* 创建目标路径所涉及到的目录,即/home/work/o2o/xxx.jpg,
* 那么 home work o2o 这三个文件夹都得自动创建
* @param targetAddr
*/
private static void makeDirPath(String targetAddr) {
String realFileParentPath = PathUtil.getImgBasePath()+targetAddr;
File dirPath = new File(realFileParentPath);
if(!dirPath.exists()) {
dirPath.mkdirs();
}
}
/**
* 生成随机文件名,当前年月日小时分钟秒+五位随机数
*/
private static String getRandomFileName() {
//获取随机的五位数
int rannum = r.nextInt(89999) + 10000;
//获取当前的年月日时分秒
String nowTimeStr = sDateFormat.format(new Date());
//随机文件名
return nowTimeStr+rannum;
}
/**
* 获取输入文件流的扩展名
* @throws IOException
*/
private static String getFileExtension(File thumbnail) {
String originalFileName = thumbnail.getName();
return originalFileName.substring(originalFileName.lastIndexOf("."));
}
}
3.1枚举类:ShopStateEnum
package com.imooc.o2o.enums;
/**结果的状态和状态标识*/
public enum ShopStateEnum {
CHECK(0,"审核中"),
OFFLINE(-1,"非法店铺"),
SUCCESS(1,"操作成功"),
PASS(2,"通过认证"),
INNER_ERROR(-1001,"内部程序错误"),
NULL_SHOPID(-1002,"ShopId为空"),
NULL_SHOP(-1003,"shop信息为空");
private int state;
private String stateInfo;
private ShopStateEnum(int state,String stateInfo){
this.state = state;
this.stateInfo = stateInfo;
}
/**
* 相当于key=state; value=stateInfo
* 根据传入的state返回相应的enum值,即状态标识:stateInfo
* values()指的是stateInfo数组
*/
public static ShopStateEnum stateOf(int state){
for(ShopStateEnum stateEnum:values()){
//获取状态结果state
if(stateEnum.getState()==state){
return stateEnum;//返回状态标识
}
}
return null;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
}
3.2 dto包的返回值类型:shop
package com.imooc.o2o.dto;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.enums.ShopStateEnum;
import java.util.List;
/**
* 添加店铺的返回类型
*/
public class ShopExecution {
//结果的状态
private int state;
//状态标识
private String stateInfo;
//店铺数量
private int count;
//操作的店铺(增删改店铺的时候用到)
private Shop shop;
//shop列表(查询店铺的时候用到)
private List<Shop> shopList;
public ShopExecution() {
}
//店铺操作失败时使用的构造器
public ShopExecution(ShopStateEnum stateEnum){
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
}
//店铺操作成功时使用的构造器
public ShopExecution(ShopStateEnum stateEnum, Shop shop){
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.shop = shop;
}
//店铺操作成功时使用的构造器
public ShopExecution(ShopStateEnum stateEnum, List<Shop> shopList){
this.state = stateEnum.getState();
this.stateInfo = stateEnum.getStateInfo();
this.shopList = shopList;
}
public int getState() {
return state;
}
public String getStateInfo() {
return stateInfo;
}
public int getCount() {
return count;
}
public Shop getShop() {
return shop;
}
public List<Shop> getShopList() {
return shopList;
}
public void setState(int state) {
this.state = state;
}
public void setStateInfo(String stateInfo) {
this.stateInfo = stateInfo;
}
public void setCount(int count) {
this.count = count;
}
public void setShop(Shop shop) {
this.shop = shop;
}
public void setShopList(List<Shop> shopList) {
this.shopList = shopList;
}
}
ShopServiceImpl.java
package com.imooc.o2o.service.Impl;
import com.imooc.o2o.dao.ShopDao;
import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.enums.ShopStateEnum;
import com.imooc.o2o.exceptions.ShopOperationException;
import com.imooc.o2o.service.ShopService;
import com.imooc.o2o.util.ImageUtil;
import com.imooc.o2o.util.PathUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.util.Date;
@Service
public class ShopServiceImpl implements ShopService {
@Autowired
private ShopDao shopDao;
/**
* @param shop 创建的店铺
* @param shopImg 用户上传的店铺图片文件
* @return 添加店铺的结果信息
*/
@Transactional//事务,方法需要事务支持
public ShopExecution addShop(Shop shop, File shopImg) {
//空值判断
if (shop == null) {
return new ShopExecution(ShopStateEnum.NULL_SHOP);
}
try {
//给店铺信息赋初始值
shop.setEnableStatus(0);//审核中,未上架
shop.setCreateTime(new Date());
shop.setLastEditTime(new Date());
int effectedNum = shopDao.insertShop(shop);//添加店铺信息
if (effectedNum <= 0) {
throw new ShopOperationException("店铺创建失败");//事务终止并回滚
} else {
//店铺创建成功
if (shopImg != null) {
//判断传入的文件是否为空,如果不为空就将图片存储到对应的目录中
try {
//根据shopId获取图片存储的相对路径
//根据相对路径给图片添加水印,并且存储在绝对路径中
addShopImg(shop, shopImg);//存储图片
} catch (Exception e) {
throw new ShopOperationException("addShopImg error" + e.getMessage());
}
//添加店铺的时候数据库中并没有添加店铺的图片地址,因此需要更新店铺信息
effectedNum = shopDao.updateShop(shop);//更新店铺的图片地址
if (effectedNum <= 0) {
throw new ShopOperationException("更新图片地址失败");
}
}
}
} catch (Exception e) {
throw new ShopOperationException("addShop error:" + e.getMessage());
}
return new ShopExecution(ShopStateEnum.CHECK, shop);
}
private void addShopImg(Shop shop, File shopImg) {
//根据shopId获取店铺图片的相对路径
String dest = PathUtil.getShopImagePath(shop.getShopId());
//给图片添加水印并将图片存储在绝对值路径中,返回图片的相对值路径
String shopImgAddr = ImageUtil.generateThumbnail(shopImg, dest);
shop.setShopImg(shopImgAddr);
}
}
为什么对添加店铺的方法添加事务?
添加店铺的方法中有三个步骤:添加店铺信息,存储图片,更新店铺信息
三个步骤中的任何一个步骤出现了问题,都希望事务进行回滚,不要将店铺信息进行添加
自己定义的异常
public class ShopOperationException extends RuntimeException {
public ShopOperationException(String msg){
super(msg);
}
}
ShopServiceTest.java
import com.imooc.o2o.BaseTest;
import com.imooc.o2o.dto.ShopExecution;
import com.imooc.o2o.entity.Area;
import com.imooc.o2o.entity.PersonInfo;
import com.imooc.o2o.entity.Shop;
import com.imooc.o2o.entity.ShopCategory;
import com.imooc.o2o.enums.ShopStateEnum;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File;
import java.util.Date;
import static org.junit.Assert.assertEquals;
public class ShopServiceTest extends BaseTest {
@Autowired
private ShopService shopService;
@Test
public void testAddShop(){
Shop shop = new Shop();
PersonInfo owner = new PersonInfo();
Area area = new Area();
ShopCategory shopCategory = new ShopCategory();
owner.setUserId(1L);
area.setAreaId(2);
shopCategory.setShopCategoryId(1L);
shop.setOwner(owner);
shop.setArea(area);
shop.setShopCategory(shopCategory);
shop.setShopName("测试的店铺1");
shop.setShopDesc("test1");
shop.setShopAddr("test1");
shop.setPhone("test1");
shop.setCreateTime(new Date());
shop.setEnableStatus(ShopStateEnum.CHECK.getState());
shop.setAdvice("审核中");
File shopImg = new File("E:/JAVA/JAVA1/javaEE/xiaoyuanshangpu/xiaohuangren.jpg");
ShopExecution shopExecution = shopService.addShop(shop, shopImg);
assertEquals(ShopStateEnum.CHECK.getState(), shopExecution.getState());
}
}
说明:需要将watermark.jpg文件放在src/test/resources目录下,才能读取到水印图片。同src/main/resources一样要与java对应
绝对路径下生成的图片,带shopId 24
E:\JAVA\JAVA1\javaEE\xiaoyuanshangpu\image\upload\item\shop\24