现在,我们需要使用springboot和layui来上传图片或者文件,springboot已经集成了文件上传功能,我们可以直接开始使用。

本次的需求是:在表单中,点击按钮上传图片,上传成功则在按钮旁边把上传的图片显示出来。

视图层

上传文件之后,需要将上传后获取的文件url路径放到一个隐藏的input中,在提交的时候提交给数据库存起来,所以,我们先在表单中放一个按钮和一个隐藏的img标签

<form id="taskAdd" class="layui-form" method="post" style="padding: 20px"
                          autocomplete="off">
                        <div class="layui-form-item">
                            <label class="layui-form-label">问题描述</label>
                            <div class="layui-input-block">
                                <textarea type="text" id="taskdesc" name="taskdesc" lay-verify="text"
                                          autocomplete="off" placeholder="请输入问题描述" class="layui-textarea"></textarea>
                            </div>

</div>

<div class="layui-form-item">
                            <label class="layui-form-label">上传照片</label>
                            <button type="button" class="layui-btn" id="uploadimg">
                                <i class="layui-icon">&#xe67c;</i>上传图片
                            </button>
                            <img id="show_up_img"  style="display: none; width: 200px;height: 100%;"  src="" />
                        </div>

<div class="layui-form-item">
                            <div class="layui-input-block">
                                <button type="submit" class="layui-btn" lay-submit=""
                                        lay-filter="cateSubBtn">立即提交</button>
                            </div>

</div>

</form>

其中的重点在下方,可以看到,我们放入了一个按钮,一个img标签,并且为img标签设置了默认不显示。

<div class="layui-form-item">
    <label class="layui-form-label">上传照片</label>
    <button type="button" class="layui-btn" id="uploadimg">
        <i class="layui-icon">&#xe67c;</i>上传图片
    </button>
    <img id="show_up_img"  style="display: none; width: 200px;height: 100%;"  src="" />
</div>

接下来,使用js来请求接口并且上传文件,上传成功后res为服务器返回的值,包括了url和实际路径,然后接着把上面的img标签填充src并且让他显示即可。

//执行实例
var uploadInst = upload.render({
    elem: '#uploadimg' //绑定元素
    ,url: '/fileUpload' //上传接口
    ,accept: 'file'
    ,method: 'POST'
    ,done: function(res){
        //上传完毕回调
        $("#show_up_img").attr("src","/upload-files/"+res.data.url).css("display","");
        layer.alert(res.data.url + " " + res.data.path);
    }
    ,error: function(){
        layer.alert("上传失败!图片限制10MB内");
        //请求异常回调
    }
});

视图的显示以及提交逻辑已经写好了,接下来,我们需要在后端处理上传的文件。

控制层

我们先设置一个上传的目录,也就是一个上传到服务器的路径,这里我先设置为D盘的一个文件夹。(当然,服务器大都是运行linux的,而linux和win的文件系统稍有不同,这部分后面再说)

D://upload-files//

在处理文件之前,我们要先配置一下路径映射,将请求的/upload-files映射到我们刚刚设置的文件夹

@Configuration
public class AdminWebConfig implements WebMvcConfigurer {

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {   // 映射资源url与本地资源路径
        registry.addResourceHandler("/upload-files/**").addResourceLocations("file:D:/upload-files/");
    }
}

接着,我们写一个post方法,来处理上传的文件,其中,为了避免中文文件名称的编码问题,将上传的文件名称截取到最后一个小数点,然后通过时间戳加上随机数的方式来避免文件名重复。

String file_suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."),file.getOriginalFilename().length());
            Random rand = new Random();
            fileNameString =  new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "_"+ (rand.nextInt(1000)+1)  + file_suffix;
            pathString = "D://upload-files//" + fileNameString;

然后使用一个Map来返回layui所需要的json的数据

Map<String,Object> map = new HashMap<>();
        Map<String,String> datas = new HashMap<>();
        datas.put("path", pathString);
        datas.put("url",fileNameString);
        //状态码如果成功返回0
        map.put("code", "0");
        //错误代码
        map.put("msg", "");
        //返回路径
        map.put("data", datas);

完整代码如下:

@PostMapping("/fileUpload")
    public Map<String,Object> fileUpload(@RequestParam(value = "file") MultipartFile file, Model model, HttpServletRequest request) {
        System.out.println(file);
        String pathString = null;
        String fileNameString = null;
        if(file!=null) {
            String file_suffix = Objects.requireNonNull(file.getOriginalFilename()).substring(file.getOriginalFilename().lastIndexOf("."),file.getOriginalFilename().length());
            Random rand = new Random();
            fileNameString =  new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "_"+ (rand.nextInt(1000)+1)  + file_suffix;
            pathString = "D://upload-files//" + fileNameString;
        }
        try {
            assert pathString != null;
            File files=new File(pathString);
            //打印查看上传路径
            System.out.println(pathString);
            if(!files.getParentFile().exists()){
                files.getParentFile().mkdirs();
            }
            file.transferTo(files);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        Map<String,Object> map = new HashMap<>();
        Map<String,String> datas = new HashMap<>();
        datas.put("path", pathString);
        datas.put("url",fileNameString);
        //状态码如果成功返回0
        map.put("code", "0");
        //错误代码
        map.put("msg", "");
        //返回实体对象集合
        map.put("data", datas);

        return map;
    }

优化

在图片上传成功之前,我们可以添加一个正常上传的状态,在网络不好的情况下就会显示加载状态

写一个函数,然后调用它

function showloading(stat) {
    if (stat) {//如果是true则显示loading
        // console.log(t);
        loading = layer.load(1, {
            shade: [0.3, '#000'], //0.1透明度的白色背景
            content:'<p style="position: relative;left: -50px;">图片上传中,请耐心等待...

',
            success: function (layerContentStyle) {
                layerContentStyle.find('.layui-layer-content').css({
                    'padding-top': '50px',
                    'text-align': 'left',
                    'line-height':'30px',
                    'color':'#fff',
                    'width': '300px'
                })
            }

        });
    }else{//如果是false则关闭loading
        // console.log("关闭loading层:" + t);
        layer.closeAll('loading');
    }
}

接着修改上传逻辑的代码,改成下面这个样子即可

var uploadInst = upload.render({
    elem: '#uploadimg' //绑定元素
    ,url: '/fileUpload' //上传接口
    ,accept: 'file'
    ,method: 'POST'
    ,before: function(input) {// 上传完成之前
        //返回的参数item,即为当前的input DOM对象
        showloading(true)
    }
    ,done: function(res){
        //上传完毕回调
        showloading(false);
        $("#show_up_img").attr("src","/upload-files/"+res.data.url).css("display","");
        layer.alert(res.data.url + " " + res.data.path);
    }
    ,error: function(){
        showloading(false);
        layer.alert("上传失败!图片限制10MB内");
        //请求异常回调
    }
});

补充

中途遇到过一次上传失败的情况,排查后发现是因为Springboot对上传的文件做了一个默认的限制,我们在yml配置文件里面修改一下即可

上传文件到jar包相对目录

使用下面的方式可以获取到当前jar包所运行的目录

String basePath = new ApplicationHome(this.getClass()).getSource().getParentFile().getPath()

参考

layui 上传图片文件时加载状态封装 | 易学教程 (e-learn.cn)

如果觉得我的文章对你有用,请随意赞赏