layui+ajax實現表單字段驗證俯抖、文件上傳

本項目使用了ajax输瓜、ssm、layui。為了實現效果為在表單輸入時判斷該字段是否在數據庫中存在以及文件上傳的功能尤揣。

  • 如下圖所示
知識編號為21的值已經在數據庫中存在搔啊,但是業(yè)務要求知識編號不能重復,所以在表單提交的時候首先需要判斷該值是否存在北戏。如果存在則提示重新輸入
知識編號字段驗證
文件上傳且支持多文件上傳负芋。并提供縮略圖。

文件上傳

準備工作

  • 我們使用的框架是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"/> <!-- 上傳文件大小上限剃毒,單位為字節(jié)(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>
  • 到這里準備工作完畢病袄,下面開始進行業(yè)務

前端界面

  • 前端使用的是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) {
                        // 異步操作執(zhí)行成功后調用的方法
                    },
                    error: function (err) {
                        // 異步操作執(zhí)行錯誤后調用的方法
                    }
                });
                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后特占,后臺控制層執(zhí)行方法成功糙置,但就是不調用success方法,一直調用error方法是目。
  • 原因:后臺返回的參數不是json類型谤饭。由于ajax規(guī)定后臺參數必須是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
                            });
                            // 信息保存成功后執(zhí)行查詢全部方法并跳轉列表界面                            
                            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' //指向一個按鈕觸發(fā)上傳,這里是指定了當用戶點擊保存表單后戏罢,一起提交
                , multiple: true // 是否開啟多文件上傳
                , accept: 'file' // 接收上傳文件的類型
                , before: function (obj) { // 上傳文件方法執(zhí)行前調用
                    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>
后臺代碼
- 業(yè)務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;
    }
- 業(yè)務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;
    }
}

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末惜浅,一起剝皮案震驚了整個濱河市瘫辩,隨后出現的幾起案子,更是在濱河造成了極大的恐慌坛悉,老刑警劉巖伐厌,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異裸影,居然都是意外死亡挣轨,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門轩猩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卷扮,“玉大人荡澎,你說我怎么就攤上這事∥钋拢” “怎么了衔瓮?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長抖甘。 經常有香客問我热鞍,道長,這世上最難降的妖魔是什么衔彻? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任薇宠,我火速辦了婚禮,結果婚禮上艰额,老公的妹妹穿的比我還像新娘澄港。我一直安慰自己,他們只是感情好柄沮,可當我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布回梧。 她就那樣靜靜地躺著,像睡著了一般祖搓。 火紅的嫁衣襯著肌膚如雪狱意。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天拯欧,我揣著相機與錄音详囤,去河邊找鬼。 笑死镐作,一個胖子當著我的面吹牛藏姐,可吹牛的內容都是我干的。 我是一名探鬼主播该贾,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼羔杨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了杨蛋?” 一聲冷哼從身側響起兜材,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎六荒,沒想到半個月后护姆,有當地人在樹林里發(fā)現了一具尸體矾端,經...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡掏击,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了秩铆。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片砚亭。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡灯变,死狀恐怖,靈堂內的尸體忽然破棺而出捅膘,到底是詐尸還是另有隱情添祸,我是刑警寧澤,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布寻仗,位于F島的核電站刃泌,受9級特大地震影響,放射性物質發(fā)生泄漏署尤。R本人自食惡果不足惜耙替,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望曹体。 院中可真熱鬧俗扇,春花似錦、人聲如沸箕别。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽串稀。三九已至除抛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間母截,已是汗流浹背镶殷。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留微酬,地道東北人绘趋。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像颗管,于是被迫代替她去往敵國和親陷遮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內容