通过easyui的filebox上传文件

news2024/11/17 3:29:28

本篇文章重点分享一下怎么通过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");
			}
		}]
	});

});

当我们选中某行数据时,点击【图片】按钮,就会打开我们的文件上传的对话框,同时如果这行记录本来的图片不为空,也会显示出来,并且设置隐藏域<input id="image" />的value为该记录的image值。

效果图片大概是这样

当我们点击上传文件后面的选择框并选择图片上传时,会提交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);
    }

}

整个项目的结构如下

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/687855.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

开源代码分享(5)—配电网重构的启发式算法(附matlab代码)

来源于文献IEEE TRANSACTIONS ON POWER SYSTEMS期刊文献的开源代码。 摘要&#xff1a;本文提出了一种两阶段的启发式计算方法&#xff0c;可以在最小的计算时间内重新配置一个径向分布网络。所有的网络交换机在操作的初始阶段都是关闭的&#xff0c;并提出了一个顺序的开关开闸…

基于SSM+jsp的教学质量评价系统设计与实现

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Origin如何绘制三维离散点并拟合曲面?

文章目录 0.引言1.准备数据2.三维离散点参数设置并绘图3.拟合曲面参数设置并绘图 0.引言 在数据统计分析中&#xff0c;有时希望知道一个因变量在两个自变量变化情况下的变化情况&#xff0c;这时可以绘制散点图&#xff0c;观察基础情况&#xff0c;进一步可以拟合散点&#x…

腾讯安全吴石:基于威胁情报构建免疫体系,助力企业稳步迈向智能安全新阶段

6月13日&#xff0c;腾讯安全、腾讯研究院联合IDC、《中国信息安全》杂志社、CIO时代、新基建创新研究院等多家权威机构、媒体共同发起“数字安全免疫力研讨论坛”&#xff0c;聚合产学研各界专家学者探讨数字安全建设新范式。论坛上&#xff0c;腾讯安全联合IDC发布“数字安全…

【物联网】使用RabbitMQ作为MQTT服务端并自定义设备连接权限

文章目录 项目背景一、部署RabbiqMQ二、设备连接鉴权1.开启插件2.修改配置3.连接鉴权4.消息鉴权 总结 项目背景 最近公司启动了一个新的物联网项目&#xff0c;使用MQTT协议与设备通信&#xff0c;在比较了各大MQTT服务后&#xff0c;决定选用开源的RabbitMQ搭建我们的服务端。…

最专业的敏捷需求管理工具推荐

为了协助大家找到合适的需求管理工具&#xff0c;我们选择了国内外几款款工具作比对&#xff1a; Leangoo领歌敏捷工具 Jama Software Visure Requirements IBM DOORS Next ReqSuite RM ReQtest Xebrio Orcanos Helix RM SpiraTeam Accompa Innoslate Leangoo领歌…

Python学习——元组

一、元组的定义 这部分就没有增、删、改操作了&#xff0c;是因为元组是一个不可变序列&#xff0c;元组也是Python内置的数据结构之一。 补充&#xff1a;关于可变序列与不可变序列 可变序列是指可以对序列进行增、删、改的操作&#xff0c;对象地址不发生变化。常见的可变序列…

【Jvm】Java类加载机制是什么?

文章目录 一、目标&#xff1a;二、原理 &#xff08;类的加载过程及其最终产品&#xff09;三、过程&#xff08;类的生命周期&#xff09;3.1、加载3.2、校验3.3、准备3.4、解析3.5、初始化 四、类加载器五、双亲委派机制 一、目标&#xff1a; 什么是类的加载&#xff1f;类…

vue3.x+elementPlus+swiper+vuedraggable实现页面装修

前言 该实现代码依赖框架&#xff1a;vue3.xelementPlusswipervuedraggable&#xff0c;做好前期工作&#xff0c;可直接在下面的附件处点击下载链接来下载相关文件&#xff1b;文件中包括搜索/图文广告/滚动消息三个模块代码示例&#xff0c;其他组件实现思路相同&#xff0c…

APT 系列 (一):APT 筑基之反射

什么是反射&#xff1f; 简单来讲&#xff0c;反射就是&#xff1a;已知一个类&#xff0c;可以获取这个类的所有信息 一般情况下&#xff0c;根据面向对象封装原则&#xff0c;Java实体类的属性都是私有的&#xff0c;我们不能获取类中的属性。但我们可以根据反射&#xff0…

问题解决 |关于CUDA的代码错误总结以及解决方法

本博客主要关于常见的CUDA的代码错误总结以及解决方法~ 1.RuntimeError运行错误 1.1.RuntimeError: CUDA error: out of memory CUDA kernel errors might be asynchronously reported at some other API call,so the stacktrace below might be incorrect. For debugging cons…

Day09 Python面向对象和异常详解

文章目录 第六章 Python面向对象6.1. 面向对象基础6.1.1. 面向对象与面向过程6.1.2. 类与对象6.1.3. 类的设计与对象的实例化6.1.4. 构造方法6.1.5. 魔术方法6.1.6. 类与类的关系使用到另一个类的对象完成需求使用到另一个类的对象作为属性 6.2. 面向对象进阶6.2.1. 封装6.2.1.…

开启AI原型设计新时代:数字创意的崭新前景

随着人工智能生成内容&#xff08;AIGC&#xff09;相关研究的突破&#xff0c;人类社会正面临一个全新的转折点。诸如多模态、可控扩散模型和大型语言模型等技术正在直接改变创意设计领域的生产过程。 在AIGC领域中&#xff0c;根据输入内容和输出形式的差异&#xff0c;我们…

【MySQl】索引及其B+树

目录 一、索引初识和测试数据的构建 二、磁盘 三、MySQL、OS、磁盘的交互方式&#xff08;InnoDB 存储引擎&#xff09; 四、MySQL中索引和page的理解 1、为什么MySQL和磁盘进行IO交互的时候&#xff0c;要采用page的方案进行交互&#xff0c;而不是采用用多少&#xff0c…

O2O跑腿快递可以解决哪些问题?

各大电商巨头都已经布局了O2O快递&#xff0c;就目前国内的快递环境而言&#xff0c;基本已经形成了四通一达局面&#xff0c;那么O2O同城配送目前有何痛点呢?下面小编就来为大家分析分析&#xff0c;感兴趣的朋友快来一起了解了解吧! 一、O2O快递目前存在哪些痛点? 我们国…

力扣题库刷题笔记14--最长公共前缀

1、题目如下&#xff1a; 2、个人Python代码实现 首先讲一下思路&#xff0c;通俗的来讲&#xff0c;就是依次比较字符串里面所有的字符&#xff0c;如果相同就是公共前缀&#xff0c;如果不同&#xff0c;后面就不用比较了&#xff0c;所以主要就是以下几点&#xff1a; 1、外…

[Leetcode] 0026. 删除有序数组中的重复项

26. 删除有序数组中的重复项 点击上方&#xff0c;跳转至Leetcode 题目描述 给你一个 升序排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。 由于在某些语…

好用到爆的数据库软件,还能兼容Excel,可以抛弃“VF”和Access

现在大部人已经不再用VF “VF”这个缩写&#xff0c;也只是停留在那个时代里&#xff0c;很多人已经不知道原来的样子&#xff0c;但有的人却还感慨万千。 懂得人自然都懂&#xff01; 微软的两款数据库软件&#xff1a;一个是office的Access&#xff0c;另一个就是“VF” VF…

自定义数据类型:结构体,枚举,联合

之前我们已经了解过结构体&#xff0c;这篇文章再来深入学习的一下&#xff0c;然后再学习其他自定义数据类型&#xff0c;枚举和联合 目录 1.结构体 1.1 结构体类型的声明 1.2 结构体的自引用 1.3 结构体变量的定义和初始化 1.4 结构体内存对齐 1.5 结构体传参 1.6 结…

【Shermo学习】使用shermo批量读入ORCA频率计算结果文件,并批量输出热力学校正数据

使用shermo批量读入ORCA频率计算结果文件&#xff0c;并批量输出热力学校正数据 安装与运行简单任务示例批量输出热力学校正数据 Shermo是北京科音自然科学研究中心卢天老师开发的一个程序&#xff0c;可以用来处理量子化学计算过程中的热力学数据。本文基于Shermo程序&#xf…