java线上文件图片资源存储方案,定时清理垃圾文件
常见的图片存储方案:1.使用nginx搭建图片服务器2.使用开源的分布式存储系统,例如Fastdfs,HDS等3.使用云存储,例如阿里云,七牛云等在实际的开发中,我们会有很多处理不同功能的服务器,例如:应用服务器:负责部署我们的应用数据库服务器:运行我们的数据库文件服务器:负责存储用户上传文件的服务器一下以使用云服务器为例:spring配置:<!--文件上传组件--><bean
常见的图片存储方案:
1.使用nginx搭建图片服务器
2.使用开源的分布式存储系统,例如Fastdfs,HDS等
3.使用云存储,例如阿里云,七牛云等
在实际的开发中,我们会有很多处理不同功能的服务器,例如:
应用服务器:负责部署我们的应用
数据库服务器:运行我们的数据库
文件服务器:负责存储用户上传文件的服务器
一下以使用云服务器为例:
spring配置:
<!--文件上传组件-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="104857600"/>
<property name="maxInMemorySize" value="4096"/>
<property name="defaultEncoding" value="UTF-8"/>
</bean>
上传文件工具类:
public class QiniuUtils {
public static String accessKey = "xxxxxxxxxx";
public static String secretKey = "xxxxxxxxxx";
public static String bucket = "存储地址名";
public static void uploadQiniu(String filePath,String fileName){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
UploadManager uploadManager = new UploadManager(cfg);
Auth auth = Auth.create(accessKey,secretKey);
String upToken = auth.uploadToken(bucket);
try{
Response response = uploadManager.put(filePath,fileName,upToken);
//解析上传成功的结果
new Gson().fromJson(response.bodyString(),DefaultPutRet.class);
}catch (QiniuException ex){
Response r = ex.response;
try{
System.err.println(r.bodyString());
}catch (QiniuException ex2){
//ignore
}
}
}
//上传文件
public static void upload2Qiniu(byte[] bytes, String fileName){
Configuration cfg = new Configuration(Zone.zone0());
//其他参数参考类注释
UploadManager uploadManager = new UploadManager(cfg);
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = fileName;
Auth auth = Auth.create(accessKey,secretKey);
String upToken = auth.uploadToken(bucket);
try{
Response response = uploadManager.put(bytes,key,upToken);
//解析上传成功的结果
DefaulPutRet putRet = new Gson().fromJson(response.bodyString(),DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);
}catch (QiniuException ex){
Response r =ex.response;
System.err.println(r.toString());
try{
System.err.println(r.bodyString());
}catch (QiniuException ex2){
//ignore
}
}
}
//删除文件
public static void deleteFileFromQiniu(String fileName){
//构造一个带指定Zone对象的配置类
Configuration cfg = new Configuration(Zone.zone0());
String key = fileName;
Auth auth = Auth.create(accessKey,secretKey);
BucketManager bucketManager = new BucketManager(auth,cfg);
try{
bucketManager.delete(bucket,key);
}catch (QiniuException ex){
System.err.println(ex.code());
System.err.println(ex.response.toString());
}
}
}
Controller类:
@RestController
@RequestMapping("/setmeal")
public class SetmealController {
//文件上传
//@RequestParam 获取文件参数,如果前端和Controller名称一致,就不用加
@RequestMapping("/upload")
public Result upload(@RequestParam("imgFile") MultipartFile imgFile){
System.out.println(imgFile); //测试
String originalFilename = imgFile.getOriginalFilename(); //获取原始文件名 abc.jpg
int index = originalFilename.lastIndexOf("."); //获取最后一个点的位置
String extention = originalFilename.substring(index - 1); //获取扩展名 .jpg
String fileName = UUID.randomUUID().toString()+extention; //避免重复,产生随机名称
try {
//将文件上传到云上
QiniuUtils.upload2Qiniu(imgFile.getBytes(),"fileName"); //文件名重复会覆盖
}catch (IOException e){
e.printStackTrace();
return new Result(false, MessageConstant.UPLOAD_FAILD);
}
return new Result(false, MessageConstant.UPLOAD_SUCCESS,fileName);
}
}
完善文件上传机制:
前面只是完成了文件上传,但是用户只是上传了图片而没有最终保存相关信息到数据库,这时上传的图片就是垃圾图片,对于这些图片我们要定时清理来释放磁盘空间,这就需要我们能够区分出来那些事垃圾图片,那些不是。
方案:
利用redis来保存图片名称,:
1.当用户上传图片后,将图片名称保存到redis的一个Set集合中,例如集合名称为setmealPicResources //只是作预览显示用
2.当用户添加套餐后,将图片名称保存到redis的另一个Set集合中,例如集合名称为setmealPicDbResources //真正提交时保存
3.计算setmealPicResources集合与setmealPicDbResources集合的差值,结果就是垃圾图片的名称集合,清理即可
spring redis配置:
<beans>
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal">
<value>200</value>
</property>
<property name="maxIdle">
<value>50</value>
</property>
<property name="testOnBorrow" value="true"/>
<property name="testOnReturn" value="true"/>
</bean>
<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg name="poolConfig" ref="jedisPoolConfig"/>
<constructor-arg name="host" value="127.0.0.1"/>
<constructor-arg name="port" value="6379" type="int"/>
<constructor-arg name="timeout" value="30000" type="int"/>
</bean>
<import resorces="spring-redis.xml"></import>
</beans>
定时任务配置
<beans>
<!--开启spring注解使用-->
<context:annotation-config></context:annotation-config>
<!--注册自定义Job-->
<bean id="ClearImgJob" class="com.xuyu.jobs.ClearImgJob"></bean>
<!--注册JobDetail,作用是负责通过反射调用指定的Job-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<!--注入目标对象-->
<property name="targetObject" ref="clearImgJob"/>
<!--注入目标方法-->
<property name="targetObject" ref="clearImg"/>
</bean>
<!--注册一个触发器,指定任务触发的时间-->
<bean id="myTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<!--注入JobDetail-->
<property name="jobDetail" ref="jobDetail"/>
<!--指定触发时间,基于Cron表达式-->
<property name="cronExpression">
<value>0 0 2 * * ?</value>
</property>
</bean>
<!--注册一个统一的调度工厂,通过这个调度工厂调度任务-->
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!--注入多个触发器-->
<property name="triggers">
<list>
<ref bean="myTrigger"/>
<ref bean="myTrigger2"/>
</list>
</property>
</bean>
</beans>
redis常量类:
public class RedisConstant {
//套餐图片所有图片名称
public static final String SETMEAL_PIC_RESOURCES = "setmealPicResources";
//套餐图片保存在数据库中的图片名称
public static final String SETMEAL_PIC_DB_RESOURCES = "setmealPicDbResources";
}
Controler更新:
@RestController
@RequestMapping("/setmeal")
public class SetmealController {
@Autowired
private JedisPool jedisPool;
@Reference
private SetmealService setmealService;
//文件上传
//@RequestParam 获取文件参数,如果前端和Controller名称一致,就不用加
@RequestMapping("/upload")
public Result upload(@RequestParam("imgFile") MultipartFile imgFile){
System.out.println(imgFile); //测试
String originalFilename = imgFile.getOriginalFilename(); //获取原始文件名 abc.jpg
int index = originalFilename.lastIndexOf("."); //获取最后一个点的位置
String extention = originalFilename.substring(index - 1); //获取扩展名 .jpg
String fileName = UUID.randomUUID().toString()+extention; //避免重复,产生随机名称
try {
//将文件上传到云上
QiniuUtils.upload2Qiniu(imgFile.getBytes(),"fileName"); //文件名重复会覆盖
return new Result(false, MessageConstant.UPLOAD_SUCCESS,fileName);
//将图片名称存入Redis,基于Redis的Set集合存储
jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_RESOURCES,fileName);
}catch (IOException e){
e.printStackTrace();
return new Result(false, MessageConstant.UPLOAD_FAILD);
}
}
}
实现类:
@Service(interfaceClass = SetmealService.class)
@Transaction
public class SetmealServiceImpl implements SetmealService {
@Autowired
private SetmealDao setmealDao;
@Autowired
private JedisPool jedisPool;
//新增套餐信息,同时需要关联检查组
public void add(Setmeal setmeal, Integer[] checkgroupIds) {
setmealDao.add(setmeal);
Integer id = setmeal.getId();
this.setSetmealAndCheckgroup(id,checkgroupIds);
//将图片名称保存到Redis集合中
String fileName = setmeal.getImg();
jedisPool.getResource().sadd(RedisConstant.SETMEAL_PIC_DB_RESOURCES);
}
//设置套餐和检查组多对多关系,操作t_setmeal_checkgroup
public void setSetmealAndCheckgroup(Integer setmealId,Integer[] checkgroupIds){
if(checkgroupIds != null && checkgroupIds.length >0){
for (Integer checkgroupId : checkgroupIds) {
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("setmealId",setmealId);
map.put("checkgroupId",checkgroupId);
setmealDao.setmealAndCheckGroup(map);
}
}
}
}
定时任务
/**
* 自定义Job,实现定时清理垃圾图片
*/
public class ClearImgJob {
@Autowired
private JedisPool jedisPool;
public void clearImg(){
//根据Redis中保存的两个set集合进行差值计算,获得垃圾图片名称集合
Set<String> set = jedisPool.getResource().sdiff(RedisConstant.SETMEAL_PIC_RESOURCES,RedisConstant.SETMEAL_PIC_DB_RESOURCES);
//遍历set集合
if(set != null){
for (String picName : set) {
//清理垃圾图片
QiniuUtils.deleteFileFromQiniu(picName);
//从Redis集合中删除图片名称
jedisPool.getResource().srem(RedisConstant.SETMEAL_PIC_RESOURCES,picName);
}
}
}
}
更多推荐
所有评论(0)