通过easyui的filebox上传文件

本篇文章重点分享一下怎么通过easyui的filebox实现文件上传的功能,从前端代码到后端接口都会展示给大家。

1、form表单同步上传

传统的文件上传会把<input type="file" />放到一个<form></form>里,设置form表单的提交方式为post,而且数据传输格式为multipart/form-data

<form method="post" action="/upload" enctype="multipart/form-data">
    请选择文件:<input type="file" name="file" />

    <input type="submit" value="提交" />
</form>

2、异步文件上传

以上是表单的同步提交,如果要实现异步文件上传的话,又该怎么做呢?

首先,说一下异步文件上传的基本思路:

文件上传框可以不放在<form>里,而是在<form>标签里面设置一个隐藏域,保存我们文件上传之后后端返回来的url,同时可以通过url回显图片。

本篇文章中,文件上传输入框放在了form表单里,方便通过easyui表单的validate方法验证必填项。

接下来开始步入正题,贴上前端页面的代码:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<link rel="stylesheet" href="/css/themes/icon.css"/>
		<link rel="stylesheet" href="/css/themes/default/easyui.css" />
		<title>法宝管理>>法宝类型列表</title>
		<script src="/js/public/jquery.min.js"></script>
		<script src="/js/easyui/jquery.easyui.min.js"></script>
		<script src="/js/easyui/easyui-lang-zh_CN.js"></script>
		<script src="/js/public/util.js"></script>
		<script src="/js/public/public.js"></script>
		<script src="/js/fabao/fabao_category_list.js"></script>
	</head>
	
	<body>
		<form id="search_form">
			<table style="border-spacing:5px;">
				<tr>
					<td><input id="_type" /></td>
					<td><input id="_name" /></td>

					<td><a id="search">搜索</a></td>
					<td><a id="clear">清空</a></td>
				</tr>
			</table>
		</form>

		<!-- 法宝类型对话框 -->
		<div id="fabao_category_dialog" style="display:none;">
			<form id="fabao_category_form">
				<input type="hidden" id="id" name="id" />

				<table style="border-spacing:5px;">
					<tr>
						<td>法宝名称</td>
						<td><input id="name" name="name" /></td>

						<td>法宝类型</td>
						<td><input id="type" name="type" /></td>
					</tr>

					<tr>
						<td>法宝信息</td>
						<td colspan="3"><input id="note" name="note" /></td>
					</tr>
				</table>
			</form>
		</div>

		<!-- 修改法宝图片对话框 -->
		<div id="upload_dialog" style="display:none;">
			<form id="upload_form">
				<input type="hidden" id="categoryId" name="id" />
				<input type="hidden" id="image" name="image" />

				<table style="border-spacing:5px;">
					<tr>
						<td>上传图片</td>
						<td><input id="upload" /></td>
					</tr>

					<tr>
						<td>图片预览</td>
						<td><img id="img" height="80" /></td>
					</tr>
				</table>
			</form>
		</div>

		<table id="fabao_category_list"></table>
	</body>
</html>

以上是一个完整页面的HTML代码,我们只需要关注以下代码片段,其中设置了一个隐藏域<input type="hidden" />用于保存文件上传的回显图片URL,当我们提交表单时,会把这个url一起提交到后台,这时候只需要完成通过ID修改图片的操作。

<div id="upload_dialog" style="display:none;">
    <form id="upload_form">
        <input type="hidden" id="categoryId" name="id" />
        <input type="hidden" id="image" name="image" />

        <table style="border-spacing:5px;">
              <tr>
                   <td>上传图片</td>
                   <td><input id="upload" /></td>
              </tr>

              <tr>
                   <td>图片预览</td>
                   <td><img id="img" height="80" /></td>
              </tr>
         </table>
     </form>
</div>

页面的js代码如下:(注意:这里的datagrid的ajax请求方式默认是get,博主修改了easyui.min.js,并把默认方式改成了post)

let requestUrl;
let types = ["主动法宝", "被动法宝"];

function addHandler() {
	requestUrl = "/fabao_category/insert";

	$("#fabao_category_dialog").dialog("open");
}

function editHandler() {
	let rowData = $("#fabao_category_list").datagrid("getSelected");
	
	if (rowData) {
		requestUrl = "/fabao_category/updateById";

		$("#id").val(rowData.id);
		$("#name").textbox("setValue", rowData.name);
		$("#type").combobox("setValue", rowData.type);
		$("#note").textbox("setValue", rowData.note);

		$("#fabao_category_dialog").dialog("open");
	} else {
		alertMsg("请选择要修改的记录!", "warning");
	}
}

function imageHandler() {
	let rowData = $("#fabao_category_list").datagrid("getSelected");

	if (rowData) {
		requestUrl = "/fabao_category/updateById";

		$("#categoryId").val(rowData.id);
		$("#image").val(rowData.image);
		$("#img").attr("src", rowData.image);

		$("#upload_dialog").dialog("open");
	} else {
		alertMsg("请选择要修改的记录!", "warning");
	}
}

$(document).ready(function() {
	$("#_type").combobox({
		width: 150,
		prompt: "法宝类型",
		panelHeight: "auto",
		data: getJsonData(types)
	});

	$("#_name").textbox({
		prompt: "请输入法宝名称"
	});

	// 搜索按钮
	$("#search").linkbutton({
		iconCls: "icon-search"
	}).click(function() {
		let type = $("#_type").combobox("getValue");
		let name = $("#_name").textbox("getValue");

		$("#fabao_category_list").datagrid("load", {
			type: type,
			name: name
		});
	});

	$("#clear").linkbutton({
		iconCls: "icon-delete"
	}).click(function() {
		$("#search_form").form("clear");
	});

	$("#name").textbox({
		width: 120,
		required: true
	});

	$("#type").combobox({
		width: 120,
		required: true,
		panelHeight: "auto",
		data: getJsonData(types)
	});

	$("#note").textbox({
		width: 314,
		height: 80,
		required: true,
		multiline: true
	});

	$("#fabao_category_dialog").dialog({
		title: "法宝信息",
		modal: true,
		closed: true,
		closable: false,
		draggable: false,
		buttons: [{
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				let selector = "#fabao_category_form";

				checkForm(selector, function () {
					let data = $(selector).serialize();

					post(requestUrl, data, function(response) {
						showMsg(response.message);

						$(selector).form("clear");
						$("#fabao_category_dialog").dialog("close");
						$("#fabao_category_list").datagrid("reload");
					}, error);
				});
			}
		}, {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				$("#fabao_category_dialog").dialog("close");
				$("#fabao_category_form").form("clear");
			}
		}]
	});

	// 文件上传框
	$("#upload").filebox({
		buttonText: "选择文件",
		width: 200,
		required: true,
		onChange: function() {
			fileUpload(this, "/fabao_category/upload");
		}
	});

	// 上传图片对话框
	$("#upload_dialog").dialog({
		title: "法宝图片",
		modal: true,
		closed: true,
		closable: false,
		draggable: false,
		buttons: [{
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				let selector = "#upload_form";

				checkForm(selector, function () {
					let data = $(selector).serialize();

					post(requestUrl, data, function(response) {
						showMsg(response.message);
						resetValue("#upload");

						$(selector).form("clear");
						$("#upload_dialog").dialog("close");
						$("#fabao_category_list").datagrid("reload");
					}, error);
				});
			}
		}, {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
                resetValue("#upload");

				$("#upload_form").form("clear");
				$("#upload_dialog").dialog("close");
			}
		}]
	});
	
	// 法宝类型数据列表
	$("#fabao_category_list").datagrid({
		url: "/fabao_category/selectByPage",
		striped: true,
		fitColumns: true,
		singleSelect: true,
		height: table_height,
		pagination: true,
		pageList: pageList,
		pageSize: pageList[0],
		loadFilter: function(result){
			if (result.code === 200){
				return result.data;
			} else {
				return null;
			}
		},
		toolbar: [{
			iconCls: "icon-add",
			text: "添加",
			handler: function() {
				addHandler()
			}
		}, "-", {
			iconCls: "icon-edit",
			text: "修改",
			handler: function() {
				editHandler();
			}
		}, "-", {
			iconCls: "icon-image",
			text: "图片",
			handler: function() {
				imageHandler();
			}
		}],
		columns: [[
			{field: "id", title: "编号", align: "center"},
			{field: "name", title: "法宝名称", align: "center", width: 100},
			{field: "type", title: "类型", align: "center", width: 100,
				formatter: function(value) {
					return "<div>" + types[value] + "</div>";
				}
			},
			{field: "image", title: "图片", align: "center", width: 40
				, formatter: function(value) {
					return "<img height='" + size + "' src='" + value + "' />";
				}
			},
			{field: "note", title: "法宝信息", align: "center", width: 400,
				formatter: function(value) {
					return "<div class='ell'>" + value + "</div>";
				}
			}
		]]
	});

});

重点看以下代码片段

let requestUrl;

function imageHandler() {
	let rowData = $("#fabao_category_list").datagrid("getSelected");

	if (rowData) {
		requestUrl = "/fabao_category/updateById";

		$("#categoryId").val(rowData.id);
		$("#image").val(rowData.image);
		$("#img").attr("src", rowData.image);

		$("#upload_dialog").dialog("open");
	} else {
		alertMsg("请选择要修改的记录!", "warning");
	}
}

$(document).ready(function() {
	$("#upload").filebox({
		buttonText: "选择文件",
		width: 200,
		required: true,
		onChange: function() {
			fileUpload(this, "/fabao_category/upload");
		}
	});

	$("#upload_dialog").dialog({
		title: "法宝图片",
		modal: true,
		closed: true,
		closable: false,
		draggable: false,
		buttons: [{
			iconCls: "icon-save",
			text: "保存",
			handler: function() {
				let selector = "#upload_form";

				checkForm(selector, function () {
					let data = $(selector).serialize();

					post(requestUrl, data, function(response) {
						showMsg(response.message);
						resetValue("#upload");

						$(selector).form("clear");
						$("#upload_dialog").dialog("close");
						$("#fabao_category_list").datagrid("reload");
					}, error);
				});
			}
		}, {
			iconCls: "icon-cancel",
			text: "取消",
			handler: function() {
				$("#upload_form").form("clear");
				$("#upload_dialog").dialog("close");
			}
		}]
	});

});

当我们选中某行数据时,点击【图片】按钮,就会打开我们的文件上传的对话框,同时如果这行记录本来的图片不为空,也会显示出来。效果图大概是这样

当我们点击上传文件后面的选择框并选择图片上传时,会提交post请求到接口"/fabao_category/upload",完成文件的上传,上传成功后会返回文件的相对路径,然后重新设置图片预览后面的图片的src属性为返回的URL。

当我们点击保存按钮时,会通过ajax的post请求的方式提交表单数据到我们的"/fabao_category/updateById"接口,就是修改法宝类型信息的接口。数据修改成功之后会刷新表格数据。

$("#fabao_category_list").datagrid("reload");

 js文件里的多个方法来自于util.js

let wkf = "该功能暂未开放,敬请期待~";
let base = "http://localhost:9091/api/mhxysy";
base = "";

/**
 * 封装的ajax get请求
 * @param url 请求url
 * @param params 请求参数
 * @param success 成功回调函数
 * @param error 失败回调函数
 * @param async 是否异步
 */
function get(url, params, success, error, async = true) {
    $.ajax({
		type: "GET",
		url: base + url,
		data: params,
		cache: false,
		async: async,
        dataType: "json",
		processData: true,
        success: success,
		error: error
    });
}

/**
 * 封装的ajax post请求
 * @param url 请求url
 * @param params 请求参数
 * @param success 成功回调函数
 * @param error 失败回调函数
 * @param async 是否异步
 */
function post(url, params, success, error, async = true) {
	$.ajax({
		type: "POST",
		url: base + url,
		data: params,
		async: async,
		cache: false,
		dataType: "json",
		processData: true,
		success: success,
		error: error
	});
}

/**
 * Ajax POST请求
 * @param url 请求路径
 * @param data 请求参数
 * @param success 成功回调
 * @param error 失败回调
 */
function ajaxPost(url, data, success, error) {
	$.ajax({
		url: base + url,
		data: data,
		cache: false,
		async: true,
		type: "POST",
		dataType: "json",
		processData: false,
		contentType: false,
		success: success,
		error: error
	});
}

let error = (res) => {
	console.log(res);

	if (res && res.responseJSON) {
		let response = res.responseJSON;

		if (res.status && res.status === 404) {
			let message;

			if(response.path) {
				message = "路径" + response.path + "不存在。";
			} else {
				message = response.message;
			}

			alertMsg(message, "error");
		} else {
			alertMsg(response.message, "error");
		}
	}
}

/**
 * 右下角弹出消息提示
 * @param message 提示消息
 * @param type 消息类型
 */
function showMsg(message, type = "slide") {
	$.messager.show({
		title: "消息",
		msg: message,
		timeout: 3000,
		showType: type
	});
}

/*
 * 弹出提示
 * @param message 提示消息
 * @param type 提示类型:warning/error/info/question
 */
function alertMsg(message, type = "info") {
	$.messager.alert("提示", message, type);
}

/**
 * 重置文件上传组件的值
 * @param selector 组件的选择器
 */
function resetValue(selector) {
	$(selector).filebox("initValue", null);
}

/**
 * 功能未开放
 */
function unopen() {
	alertMsg(wkf);
}

function unselected() {
	alertMsg("请选择一条记录!", "warning");
}

function fileUpload(_obj, url) {
	let file = $(_obj).context.ownerDocument.activeElement.files[0];
	let form = new FormData();

	form.append("file", file);

	ajaxPost(url, form, function (result) {
		let image = result.data;

		$("#image").val(image);
		$("#img").attr("src", image);
	}, error);
}

/**
 * 验证表单
 * @param selector 选择器
 * @param func 表单验证通过后执行的操作
 */
function checkForm(selector, func) {
	let $form = $(selector);
	let bool = $form.form("validate");

	if (bool) {
		func();
	} else {
		alertMsg("请填写正确的表单项", "warning");
	}
}

/**
 * 根据数组获取json格式的数据
 * @param arr
 */
function getJsonData(arr) {
	let jsonData = [];

	for (let i = 0; i < arr.length; i++) {
		let elem = {"value": i + "", "text": arr[i]};

		jsonData.push(elem);
	}

	return jsonData;
}

/**
 * 初始化easyui数据列表datagrid
 * @param selector 选择器
 * @param url 加载数据的URL
 * @param toolbar 头部工具栏
 * @param columns 表格的列
 * @param height 表格高度
 * @param pageList 分页参数
 * @param rownumbers 是否显示行号
 */
function asDatalist(selector, url, toolbar, columns, height = 432, pageList = [10, 20, 50, 100], rownumbers = false) {
	$(selector).datagrid({
		url: url,
		striped: true,
		height: height,
		fitColumns: true,
		singleSelect: true,
		rownumbers: rownumbers,
		pagination: true,
		pageList: pageList,
		pageSize: pageList[0],
		loadFilter: function(result){
			if (result.code === 200){
				return result.data;
			} else {
				return null;
			}
		},
		toolbar: toolbar,
		columns: columns
	});
}

接下来看一下后端的接口怎么写的:

FabaoCategoryController.java

package cn.edu.sgu.www.mhxysy.controller.fabao;

import cn.edu.sgu.www.mhxysy.restful.JsonResult;
import cn.edu.sgu.www.mhxysy.restful.PageResult;
import cn.edu.sgu.www.mhxysy.entity.fabao.FabaoCategory;
import cn.edu.sgu.www.mhxysy.pager.fabao.FabaoCategoryPager;
import cn.edu.sgu.www.mhxysy.service.fabao.FabaoCategoryService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;

@RestController
@Api(tags = "法宝类型控制器类")
@RequestMapping(path = "/fabao_category", produces="application/json; charset=utf-8")
public class FabaoCategoryController {
	private final FabaoCategoryService service;

	@Autowired
	public FabaoCategoryController(FabaoCategoryService service) {
		this.service = service;
	}

	@ApiOperation("添加法宝类型")
	@RequestMapping(value = "/insert", method = RequestMethod.POST)
	public JsonResult<Void> insert(FabaoCategory category) {
		service.insert(category);

		return JsonResult.success("添加成功");
	}

	@ApiOperation("通过id修改法宝类型信息")
	@RequestMapping(value = "/updateById", method = RequestMethod.POST)
	public JsonResult<Void> updateById(FabaoCategory category) {
		service.updateById(category);

		return JsonResult.success("修改成功");
	}

	@ApiOperation("查询全部法宝类型")
	@RequestMapping(value = "/selectAll", method = RequestMethod.GET)
	public List<FabaoCategory> selectAll() {
		return service.selectAll();
	}

	@ApiOperation("通过id查询法宝类型信息")
	@RequestMapping(value = "/selectById", method = RequestMethod.GET)
	public FabaoCategory selectById(@RequestParam Integer id) {
		return service.selectById(id);
	}

	@ApiOperation("分页查询法宝类型列表")
	@RequestMapping(value = "/selectByPage", method = RequestMethod.POST)
	public JsonResult<PageResult<FabaoCategory>> selectByPage(FabaoCategoryPager pager) {
		Page<FabaoCategory> result = service.selectByPage(pager);

		return JsonResult.restPage(result);
	}

	@ApiOperation("上传图片")
	@RequestMapping(value = "/upload", method = RequestMethod.POST)
	public JsonResult<String> upload(MultipartFile file) throws IOException {
		String url = service.upload(file);

		return JsonResult.success(null, url);
	}

}

 FabaoCategoryServiceImpl.java

package cn.edu.sgu.www.mhxysy.service.fabao.impl;

import cn.edu.sgu.www.mhxysy.util.StringUtils;
import cn.edu.sgu.www.mhxysy.base.Pager;
import cn.edu.sgu.www.mhxysy.consts.DirectoryConsts;
import cn.edu.sgu.www.mhxysy.entity.fabao.FabaoCategory;
import cn.edu.sgu.www.mhxysy.mapper.fabao.FabaoCategoryMapper;
import cn.edu.sgu.www.mhxysy.pager.fabao.FabaoCategoryPager;
import cn.edu.sgu.www.mhxysy.service.fabao.FabaoCategoryService;
import cn.edu.sgu.www.mhxysy.util.UploadUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.List;

/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class FabaoCategoryServiceImpl implements FabaoCategoryService {
	private final UploadUtils uploadUtils;
	private final FabaoCategoryMapper mapper;

	@Autowired
	public FabaoCategoryServiceImpl(UploadUtils uploadUtils, FabaoCategoryMapper mapper) {
		this.uploadUtils = uploadUtils;
		this.mapper = mapper;
	}

	@Override
	public void insert(FabaoCategory category) {
		mapper.insert(category);
	}

	@Override
	public void updateById(FabaoCategory category) {
		mapper.updateById(category);
	}

	@Override
	public List<FabaoCategory> selectAll() {
		return mapper.selectList(null);
	}

	@Override
	public FabaoCategory selectById(Integer id) {
		return mapper.selectById(id);
	}

	@Override
	public Page<FabaoCategory> selectByPage(FabaoCategoryPager pager) {
		QueryWrapper<FabaoCategory> wrapper = new QueryWrapper<>();
		Page<FabaoCategory> page = Pager.ofPage(pager);

		wrapper.eq(
				pager.getType() != null,
				"type", pager.getType()
		);
		wrapper.like(
				StringUtils.isNotEmpty(pager.getName()),
				"name", pager.getName()
		);

		return mapper.selectPage(page, wrapper);
	}

	@Override
	public String upload(MultipartFile file) throws IOException {
		String directory = DirectoryConsts.DIRECTORY_FABAO;

		return uploadUtils.upload(file, directory);
	}

}

DirectoryConsts.java

DirectoryConsts就是一个存放常量的接口,保存项目用到的文件上传的相对路径

package cn.edu.sgu.www.mhxysy.consts;

/**
 * 常量工具类
 * 定义了项目用到的文件上传路径相对根路径root的文件夹
 */
public interface DirectoryConsts {
    /**
     * 角色图片上传文件夹
     */
    String DIRECTORY_ROLE = "/role/head";

    /**
     * 烹饪图片上传文件夹
     */
    String DIRECTORY_CUISINE = "/cuisine";

    /**
     * 药品图片上传文件夹
     */
    String DIRECTORY_MEDICINE = "/medicine";

    /**
     * 角色日常记录图片上传文件夹
     */
    String DIRECTORY_DAILY_RECORD = "/daily_record";

    /**
     * 角色时装图片上传文件夹
     */
    String DIRECTORY_ROLE_SHIZHUANG = "/role_shizhuang";

    /**
     * 特技图片上传文件夹
     */
    String DIRECTORY_TETJ = "/teji";

    /**
     * 法宝图片上传文件夹
     */
    String DIRECTORY_FABAO = "/fabao";

    /**
     * 坐骑图片上传文件夹
     */
    String DIRECTORY_ZUOQI = "/zuoqi";

    /**
     * 门派图片上传文件夹
     */
    String DIRECTORY_SCHOOL = "/school";

    /**
     * 门派法宝图片上传文件夹
     */
    String DIRECTORY_SCHOOL_FABAO = "/school_fabao";

    /**
     * 器灵图片上传文件夹
     */
    String DIRECTORY_QILING = "/qiling";

    /**
     * 宠物图片上传文件夹
     */
    String DIRECTORY_CHONGWU = "/chongwu";

    /**
     * 助战图片上传文件夹
     */
    String DIRECTORY_PARTNER = "/partner";

    /**
     * 助战图片上传文件夹
     */
    String DIRECTORY_PARTNER_SKILL = "/partner_skill";

    /**
     * 装备图片上传文件夹
     */
    String DIRECTORY_EQUIPMENT = "/equipment";

    /**
     * 修炼技能图片上传文件夹
     */
    String DIRECTORY_XIULIAN = "/xiulian";

    /**
     * 变身卡图片上传文件夹
     */
    String DIRECTORY_BIANSHENKA = "/bianshenka";

    /**
     * 坐骑技能图片上传文件夹
     */
    String DIRECTORY_ZUOQI_SKILL = "/zuoqi_skill";

    /**
     * 门派技能图片上传文件夹
     */
    String DIRECTORY_SCHOOL_SKILL = "/school_skill";

    /**
     * 宠物技能图片上传文件夹
     */
    String DIRECTORY_CHONGWU_SKILL = "/chongwu_skill";

    /**
     * 宠物内丹图片上传文件夹
     */
    String DIRECTORY_CHONGWU_NEIDAN = "/chongwu_neidan";

    /**
     * 宠物套装技能图片上传文件夹
     */
    String DIRECTORY_CHONGWU_TAOZHUANG = "/chongwu_taozhuang";

    /**
     * 宠物专属内丹图片上传文件夹
     */
    String DIRECTORY_ZHUANSHUNEIDAN = "/zhuanshu_neidan";

    /**
     * 器灵套装图片上传文件夹
     */
    String DIRECTORY_QILING_TAOZHUANG = "/qiling_taozhuang";

    /**
     * 宠物装备图片上传文件夹
     */
    String DIRECTORY_CHONGWU_EQUIPMENT = "/chongwu_equipment";

    /**
     * 器灵套装图片上传文件夹
     */
    String DIRECTORY_QILING_TAOZHUANG_IMAGE = "/qiling_taozhuang_image";

    /**
     * 星印图片上传文件夹
     */
    String DIRECTORY_XINGYIN = "/xingyin";

    /**
     * 星印图片上传文件夹
     */
    String DIRECTORY_XINGYIN_SKILL = "/xingyin_skill";

    /**
     * 星印特效图片上传文件夹
     */
    String DIRECTORY_XINGYIN_TEXIAO = "/xingyin_texiao";

    /**
     * 装备制造书图片上传文件夹
     */
    String DIRECTORY_FORGE_BOOK = "/forge_book";
}

UploadUtils.java

UploadUtils是文件上传工具类,定义为组件,因为要读取配置文件

package cn.edu.sgu.www.mhxysy.util;

import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;

/**
 * 文件上传工具类
 * @author heyunlin
 * @version 1.0
 */
@Component
public class UploadUtils {
    /**
     * 文件上传根路径
     */
    @Value("${uploads.path}")
    private String root;

    public String getRoot() {
        return root;
    }

    /**
     * 图片上传
     * @param file MultipartFile对象
     * @param directory 文件上传目录
     * @return JsonResult<String>
     */
    public String upload(MultipartFile file, String directory) throws IOException {
        boolean result = check(file);

        if (result) {
            // 获取文件名
            String fileName = StringUtils.getFileName(file);
            // 创建目标对象
            File targetFile = new File(root + directory, fileName);

            // 保存文件
            file.transferTo(targetFile);

            return directory + "/" + fileName;
        }

        return null;
    }

    /**
     * 检查文件格式
     * @param file MultipartFile
     */
    private boolean check(MultipartFile file) {
        if (file == null) {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "您未上传任何图片!");
        }

        String filename = file.getOriginalFilename();

        if (StringUtils.isNotEmpty(filename)) {
            String fileType = StringUtils.getFileType(filename).toLowerCase();

            // 图片文件名后缀
            String picPrefix = ".webp,.jpeg,.jpg,.png";

            if (!picPrefix.contains(fileType)) {
                throw new GlobalException(ResponseCode.BAD_REQUEST, "只允许上传格式为" + picPrefix + "的图片");
            }

            return true;
        } else {
            throw new GlobalException(ResponseCode.BAD_REQUEST, "获取上传的文件名失败~");
        }
    }

}

StringUtils.java

这是字符串工具类,封装常用的字符串相关方法

package cn.edu.sgu.www.mhxysy.util;

import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * String工具类
 * @author heyunlin
 * @version 1.0
 */
public class StringUtils {
    /**
     * 判断字符串是否为null或""
     * 字符串为""或null返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isEmpty(String str) {
        return str == null || str.isEmpty() || isBlank(str);
    }

    /**
     * 判断字符串是否为""或null
     * 字符串为""或null返回false,否则返回true
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * 判断字符串是否为空白字符
     * 字符串为空白字符返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isBlank(String str) {
        return str.trim().length() == 0;
    }

    /**
     * 判断字符串是否不是空白字符
     * 字符串不是空白字符返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isNotBlank(String str) {
        return !isBlank(str);
    }

    /**
     * 判断字符串是否为null或""
     * 字符串为""或null返回true,否则返回false
     * @param str 要判断的字符串
     * @return boolean
     */
    public static boolean isNullOrEmpty(String str) {
        return str == null || str.isEmpty();
    }

    /**
     * 检查字符串是否包含空白字符
     * 如果不包含空格返回true,否则返回false
     * @param str 需要比较的字符串
     * @return boolean
     */
    public static boolean check(String str) {
        // 去除空白字符后字符串的长度
        int realLength = str.replaceAll("\\s", "").length();
        // 字符串原来的长度
        int originalLength = str.length();

        return realLength == originalLength;
    }

    /**
     * 根据当前时间生成UUID
     * @return String
     */
    public static String uuid() {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        LocalDateTime localDate = LocalDateTime.now();

        return localDate.format(formatter);
    }

    /**
     * 通过文件名获取文件类型
     * @param fileName 文件名
     */
    public static String getFileType(String fileName) {
        // 得到文件名中最后一次出现"."的位置
        int index = fileName.lastIndexOf('.');

        // 文件类型统一转换为小写
        return fileName.substring(index).toLowerCase();
    }

    /**
     * 获取文件名
     * @param filename String
     * @return String 由当前时间生成的新文件名
     */
    public static String getFileName(String filename) {
        // 返回uuid.文件类型,如:20220618131456.jpg
        return uuid() + getFileType(filename);
    }

    /**
     * 获取文件名
     * @param file MultipartFile对象
     * @return String 由当前时间生成的新文件名
     */
    public static String getFileName(MultipartFile file) {
        // 得到上传文件的原始文件名
        String filename = file.getOriginalFilename();

        // 判断文件名是否为空
        if (isNullOrEmpty(filename)) {
            throw new RuntimeException("获取文件名失败!");
        }

        // 返回uuid.文件类型,如:20220618131456.jpg
        return uuid() + getFileType(filename);
    }

    /**
     * 驼峰命名转下划线命名
     * @param str 待转换的字符串
     * @return String
     */
    public static String toLowerCase(String str) {
        // 小写和大写紧挨一起的地方加上分隔符_,然后全部转为小写
        str = str.replaceAll("([a-z])([A-Z])", "$1_$2");

        return str.toLowerCase();
    }

    /**
     * 下划线命名转驼峰命名
     * @param str 待转换的字符串
     * @return String
     */
    private static String toUpperCase(String str) {
        // 将下划线替换为空格
        StringBuilder under= new StringBuilder();
        str = str.toLowerCase().replace("_", " ");

        // 将字符串根据空格分割成数组
        String[] array = str.split(" ");

        // 将每个单词首字母大写
        for (String s : array) {
            String letter = s.substring(0, 1).toUpperCase() + s.substring(1);

            under.append(letter);
        }

        return under.toString();
    }

}

最后是统一自定义异常GlobalException

package cn.edu.sgu.www.mhxysy.exception;

import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 自定义异常
 * @author heyunlin
 * @version 1.0
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class GlobalException extends RuntimeException {
    private ResponseCode responseCode;

    public GlobalException(ResponseCode responseCode, String message) {
        super(message);

        setResponseCode(responseCode);
    }

}

配合全局异常处理类,就可以在项目运行过程时发生异常主动捕获,并调用对应的异常处理方法返回响应对象

package cn.edu.sgu.www.mhxysy.exception.handler;

import cn.edu.sgu.www.mhxysy.restful.JsonResult;
import cn.edu.sgu.www.mhxysy.restful.ResponseCode;
import cn.edu.sgu.www.mhxysy.exception.GlobalException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletResponse;

/**
 * 全局异常处理类
 * @author heyunlin
 * @version 1.0
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理GlobalException
     * @param e GlobalException
     * @return JsonResult<Void>
     */
    @ExceptionHandler(GlobalException.class)
    public JsonResult<Void> handlerGlobalException(HttpServletResponse response, GlobalException e) {
        System.err.println(e.getMessage());
        e.printStackTrace();
        response.setStatus(e.getResponseCode().getValue());

        return JsonResult.error(e.getResponseCode(), e);
    }

    /**
     * 处理BindException
     * @param e BindException
     * @return JsonResult<Void>
     */
    @ExceptionHandler(BindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public JsonResult<Void> handlerBindException(BindException e) {
        e.printStackTrace();

        BindingResult bindingResult = e.getBindingResult();
        FieldError fieldError = bindingResult.getFieldError();
        assert fieldError != null;
        String defaultMessage = fieldError.getDefaultMessage();

        return JsonResult.error(ResponseCode.BAD_REQUEST, defaultMessage);
    }

    /**
     * 处理Exception
     * @param e Exception
     * @return JsonResult<Void>
     */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public JsonResult<Void> handlerException(Exception e) {
        e.printStackTrace();

        return JsonResult.error(ResponseCode.ERROR, e);
    }

}

整个项目的结构如下

 好了,这篇文章就分享到这里了,如果文章对你有所帮助,不要忘了点赞+收藏哦~

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值