layui+ajax实现表单字段验证、文件上传

本项目使用了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;
    }
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容