本项目使用了ajax、ssm、layui。为了实现效果为在表单输入时判断该字段是否在数据库中存在以及文件上传的功能。
- 如下图所示
知识编号为21的值已经在数据库中存在,但是业务要求知识编号不能重复,所以在表单提交的时候首先需要判断该值是否存在。如果存在则提示重新输入
文件上传且支持多文件上传。并提供缩略图。
准备工作
- 我们使用的框架是ssm即springMVC + spring + mybatis ,使用了maven来构建项目。并且使用了json解析格式。
第一步:在pom.xml文件引入依赖坐标
<!-- 文件上传 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
<!-- json配置 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>jsr250-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.8</version>
</dependency>
第二步:在spirng的配置文件applicationContext.xml文件中引入文件上传所需的multipartResolver对象
<!--文件上传配置-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 请求的编码格式,必须和jSP的pageEncoding属性一致,以便正确读取表单的内容, 默认为ISO-8859-1 -->
<property name="defaultEncoding" value="utf-8"/> <!-- 上传文件大小上限,单位为字节(10485760=10M) -->
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>
第三步:在spirngmvc的配置文件springmvc.xml文件中配置json
<!--配置json-->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html; charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>text/html; charset=UTF-8</value>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</list>
</property>
</bean>
- 到这里准备工作完毕,下面开始进行业务
前端界面
- 前端使用的是JSP界面,使用的layui前端框架快速搭建
- 由于在这个页面,使用了表单数据验证、文件上传、表单提交
表单样式
<form id="addForm" class="layui-form" action="#"
method="post">
<div class="layui-form-item">
<label class="layui-form-label">知识编号</label>
<div class="layui-input-inline shortInput">
<input type="text" id="kId" name="kId" autocomplete="off" placeholder="请输入知识编号,例:SS002"
class="layui-input" lay-verify="inputKId">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">知识名称</label>
<div class="layui-input-inline shortInput">
<input type="text" id="kName" name="kName" autocomplete="off" placeholder="请输入知识名称" class="layui-input">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">知识描述</label>
<div class="layui-input-inline shortInput">
<textarea style="width: 100%;" placeholder="请输入内容" id="kDescribe" class="layui-textarea" name="kDescribe"></textarea>
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">知识价格</label>
<div class="layui-input-inline shortInput">
<input type="text" id="kPrice" name="kPrice" autocomplete="off" placeholder="请输入知识价格"
class="layui-input" required
lay-verify="required|number">
</div>
</div>
<div class="layui-form-item">
<label class="layui-form-label">知识文件</label>
<div class="layui-upload">
<button type="button" class="layui-btn" id="uploadFile">请选择文件</button>
<blockquote class="layui-elem-quote layui-quote-nm" style="margin-top: 10px;">
预览图:
<div class="layui-upload-list" id="previewImages"></div>
</blockquote>
<button id="hideUpload" type="button" style="display: none"></button>
</div>
</div>
<hr class="layui-bg-blue">
<div class="layui-form-item">
<div class="layui-input-block">
<button id="btnAction" class="layui-btn" lay-submit="" lay-filter="submit">保存</button>
<button type="reset" class="layui-btn layui-btn-primary">重置</button>
</div>
</div>
</form>
ajax使用
- 在js这里,因为我们使用了layui。所以我们首先提供layui.use([可选模块],function{})方法引入模块。再定义layui模块使用函数
- 在ajax里,我们需要配置以下:
// 调用ajax进行异步提交
$.ajax({
type: 'post',
dataType: "json",
url: '', // 你的url地址
//async: true, 是否开启异步操作,默认为ture,为异步调用。false为同步调用
data: {}, // 需要传输到后台的数据
success: function (res) {
// 异步操作执行成功后调用的方法
},
error: function (err) {
// 异步操作执行错误后调用的方法
}
});
return false; // 关闭操作,否则无法刷新数据
});
注意: 使用ajax通常会遇到几个问题:
1.使用ajax向后台传参问题:
- data这里使用的是key:value的传参方式。比如后台springMVC的控制层需要获取userId的值。则data定义为:
data: {
userId: value // value为前端参数
}
data里面的key需要与后台接收参数定义一致,否则后台无法接收参数
- 后台如果需要通过对象的形式获取参数,例如异步表单提交。则data定义为:
data: {
user: {
userId : value
name: value
}
}
2.使用ajax后,后台控制层执行方法成功,但就是不调用success方法,一直调用error方法。
- 原因:后台返回的参数不是json类型。由于ajax规定后台参数必须是json类型,如果返回的参数(列表,对象)都正确,因为不是json类型,则一样调用error方法。
- 解决: 后台使用map返回,使用@ResponseBody注解
@RequestMapping("拦截路径")
@ResponseBody
public Object findByMId(String mId) throws Exception {
HashMap<String, Object> map = new HashMap<>();
// 方法省略
return map;
}
js代码
<script>
layui.use(["jquery", "upload", "form", "layer", "element"], function () {
var $ = layui.$,
element = layui.element,
layer = layui.layer,
upload = layui.upload,
form = layui.form;
// 验证表单字段是否存在
form.verify({
inputKId: function (value) {
var knowledge = {
kId: value
};
var message = '';
$.ajax({
type: "post",
url: "${pageContext.request.contextPath}/knowledge/toVerifyByKId.do",
dataType: 'json',
async: false,
data: knowledge,
success: function (data) {
if (data) {
} else {
message = "知识编号已存在请重新输入!"
}
}
});
if (message !== "") {
return message
}
}
});
// 表单提交事件
form.on('submit(submit)', function (data) {
var date = new Date();
var knowledge = {
kId: data.field.kId,
kName: data.field.kName,
kDescribe: data.field.kDescribe,
kPrice: data.field.kPrice,
};
// 调用ajax进行异步提交
$.ajax({
type: 'post',
dataType: "json",
url: '${pageContext.request.contextPath}/knowledge/addKnowledge.do',
data: knowledge,
success: function (res) {
if (res.code == 0) {
$('#hideUpload').trigger('click');
layer.msg("知识信息保存成功!", {
time: 3000
});
// 信息保存成功后执行查询全部方法并跳转列表界面
location.href="${pageContext.request.contextPath}/knowledge/findAll.do";
} else {
layer.msg("知识信息保存失败!请重新填写!", {
time: 3000
}, function () {
//重新加载页面
location.reload();
})
}
},
error: function (err) {
}
});
return false;
});
// layui文件上传方法
var uploadInst = upload.render({
elem: '#uploadFile' // id选择器,用于指向文件上传的div样式
, url: '${pageContext.request.contextPath}/knowledge/uploadFile.do' // 请求后台的路径
, auto: false //选择文件后不自动上传
, bindAction: '#hideUpload' //指向一个按钮触发上传,这里是指定了当用户点击保存表单后,一起提交
, multiple: true // 是否开启多文件上传
, accept: 'file' // 接收上传文件的类型
, before: function (obj) { // 上传文件方法执行前调用
this.data = {'kId': $('#kId').val()}; // 获取主键,并方便保存至文件表数据库
}
, choose: function (obj) { // 选择文件后调用,用于显示缩略图
//将每次选择的文件追加到文件队列
var files = obj.pushFile();
//预读本地文件,如果是多文件,则会遍历。(不支持ie8/9)
obj.preview(function (index, file, result) {
$('#previewImages').append('<img src="' + result + '" alt="' + file.name + '" class="layui-upload-img" style="height: 100px;width: 140px;margin-left: 10px;margin-right: 10px">')
});
}
, done: function (res) { // 上传以后调用
//上传完毕
layer.msg("文件上传成功!", {
time: 3000
});
}
,error: function(index, upload){ // 上传文件失败时调用
layer.closeAll('loading');
}
});
});
</script>
后台代码
- 业务1:判断知识编号是否已存在,如存在则提示信息。
controller
/**
* 判断知识编号是否存在
*/
@RequestMapping("/toVerifyByKId.do")
@ResponseBody
public boolean toVerifyByKId(Knowledge knowledge){
String KId = knowledge.getkId();
if (KId!=null) {
List<Knowledge> knowledge1 = knowledgeService.findByKId(KId);
System.out.println(knowledge1);
if (knowledge1.size()==0) {
return true;
}
}
System.out.println("知识编号存在");
return false;
}
- 业务2:文件上传(支持多文件)。
controller这里通过MultipartFile 接收一个file对象,注意不是数组[]类型,因为在layui里,上传文件是单独调用。一个文件上传就调用一次上传文件的方法。如果是三个文件上传,那么就调用三次文件上传的方法。
/**
* 上传知识文件
*/
@RequestMapping("/uploadFile.do")
@ResponseBody
@CrossOrigin
public int uploadFile(@RequestParam("file") MultipartFile file , String kId) throws Exception {
int code = -1;
if (file != null) {
code = knowledgeFileService.uploadFile(file,kId);
}
return code;
}
serviec这里使用文件上传工具类
/**
* 上传文件
*
* @param file
* @param kId
*/
@Override
public int uploadFile(MultipartFile file, String kId) throws Exception {
int code = -1;
String path = "D:\\ideaTestFile\\knowpay";
if (!"".equals(kId) && kId != null) {
// 获取文件名
String fileName = file.getOriginalFilename();
if (fileName != null) {
// 上传文件
upLoadUtil(path,fileName,file);
// 获取文件类型(后缀)
String[] splitStr = fileName.split("\\.");
String suffix = splitStr[splitStr.length - 1];
// 获取文件路径
String filePath = path + "\\" +fileName;
// 保存数据库
KnowledgeFile knowledgeFile = new KnowledgeFile();
knowledgeFile.setkId(kId);
knowledgeFile.setfName(fileName);
knowledgeFile.setfType(suffix);
knowledgeFile.setfPath(filePath);
knowledgeFileDao.addKnowledgeFile(knowledgeFile);
code = 0;
}
}
return code;
}
FileUtils文件操作工具类
package com.ozy.utils;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URLEncoder;
/**
* 文件操作工具类
*/
public class FileUtils {
/**
* 上传文件工具
*
* @param UPLOAD_FILES_PATH 上传路径
* @param fileName 文件名称
* @param file 文件
*/
public static Boolean upLoadUtil(String UPLOAD_FILES_PATH, String fileName, MultipartFile file) throws IOException {
if (file.isEmpty()) {
return false;
} else {
File dest = new File(UPLOAD_FILES_PATH + "/" + fileName);
//判断文件父目录是否存在
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
file.transferTo(dest);
}
return true;
}
/**
* 下载文件工具
*
* @param response response对象
* @param realPath 文件路径
* @param fileName 文件名称
*/
public static void downloadUtil(final HttpServletResponse response, String realPath, String fileName) throws IOException {
File file = new File(realPath);
if (file.exists()) {
response.setHeader("content-type", "application/octet-stream");
response.setContentType("application/octet-stream");
// 下载文件能正常显示中文
try {
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
// 实现文件下载
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
assert bis != null;
bis.close();
fis.close();
}
}
}
/**
* 删除文件夹
*
* @param sPath 文件夹路径
*/
public static boolean DeleteFolder(String sPath) {
boolean flag = false;
File file = new File(sPath);
// 判断目录或文件是否存在
if (!file.exists()) { // 不存在返回 false
return flag;
} else {
// 判断是否为文件
if (file.isFile()) { // 为文件时调用删除文件方法
return deleteFile(sPath);
} else { // 为目录时调用删除目录方法
return deleteDirectory(sPath);
}
}
}
/**
* 删除单个文件
*
* @param sPath 被删除文件的文件名
* @return 单个文件删除成功返回true,否则返回false
*/
public static boolean deleteFile(String sPath) {
boolean flag = false;
File file = new File(sPath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
flag = true;
}
return flag;
}
/**
* 删除目录(文件夹)以及目录下的文件
*
* @param sPath 被删除目录的文件路径
* @return 目录删除成功返回true,否则返回false
*/
public static boolean deleteDirectory(String sPath) {
//如果sPath不以文件分隔符结尾,自动添加文件分隔符
if (!sPath.endsWith(File.separator)) {
sPath = sPath + File.separator;
}
File dirFile = new File(sPath);
//如果dir对应的文件不存在,或者不是一个目录,则退出
if (!dirFile.exists() || !dirFile.isDirectory()) {
return false;
}
boolean flag = true;
//删除文件夹下的所有文件(包括子目录)
File[] files = dirFile.listFiles();
for (int i = 0; i < files.length; i++) {
//删除子文件
if (files[i].isFile()) {
flag = deleteFile(files[i].getAbsolutePath());
if (!flag) {
break;
}
} //删除子目录
else {
flag = deleteDirectory(files[i].getAbsolutePath());
if (!flag) {
break;
}
}
}
if (!flag) {
return false;
}
//删除当前目录
if (dirFile.delete()) {
return true;
} else {
return false;
}
}
/**
* 转文件格式
*
* @param img 照片文件
*/
public static byte[] fileToByte(File img) throws Exception {
byte[] bytes = null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
BufferedImage bi;
bi = ImageIO.read(img);
ImageIO.write(bi, "jpg", baos);
bytes = baos.toByteArray();
} catch (Exception e) {
// e.printStackTrace();
} finally {
// 关闭输出流
baos.close();
}
return bytes;
}
}