spring boot 开发笔记——图片上传显示篇(上传)

效果展示

上传界面
在这里插入图片描述
上传成功响应
在这里插入图片描述
页面显示
在这里插入图片描述

项目环境说明

开发框架:spring boot 2 +themeleaf+MySQL8.5+JDBC JPA
开发语言及版本:Java1.8
开发工具:IntelliJ IDEA 2019+HBuilder X+Navicat

需求说明

  1. 用户可以批量上传图片
  2. 选择上传图片后会判断是否符合图片格式,图片大小是否合适。图片会显示在页面供用户浏览。
  3. 上传图片内容存放在项目目录下static下的photos下,并且图片路径存放在数据库中,多张图片用 ‘;’ 进行分隔。
  4. 能够从数据库中根据‘;’分隔符读出用户上传图片。

详细设计

  1. 项目目录及依赖说明
    项目目录 说明:controller层是控制层,entity 是实体类层,repository相当于dao层,service是业务逻辑层,util是工具层,static里面存放的静态资源,templates里面是网页。
    controller层就是控制层,entity 是实体类,repository相当于dao层,service是业务逻辑层,util是工具层
    依赖导入,pom.xml 代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>renren</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>renren</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.2</version>
        </dependency>
   

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>


配置文件application.properties


spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/spring_renren?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
#display sql in console
spring.jpa.show-sql=true
#format json
spring.jackson.serialization.indent-output=true

server.port=8080
#数据库类型为mysql
spring.datasource.dbType=mysql
#启动时初始化5个连接
spring.datasource.initialSize=20
#最小空闲连接5个
spring.datasource.minIdle=5
#最大连接数量20
spring.datasource.maxActive=20
#获取连接等待时间60秒,超出报错
spring.datasource.maxWait=60000
#每60秒执行一次连接回收器
spring.datasource.timeBetweenEvictionRunsMillis=60000
#5分钟内没有任何操作的空闲连接会被回收
spring.datasource.minEvictableIdleTimeMillis=300000
#验证连接有效性的SQL
spring.datasource.validationQuery=select 'x'
#空闲时校验,建议开启
spring.datasource.testWhileIdle=true
#使用中是否校验有效性,推荐关闭
spring.datasource.testOnBorrow=false
#归还连接时校验有效性,推荐关闭
spring.datasource.testOnReturn=false
spring.datasource.poolPreparedStatements=false
#设置过滤器,stat用于接收状态,wall用于防止SQL注入,logback则说明使用logback日志输出
spring.datasource.filters=stat,wall,logback
#统计所有数据源状态
spring.datasource.useGlobalDataSourceStat=true
#sql合并统计,与设置慢SQL时间为500毫秒
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

#这里设置了静态资源的访问路径
server.servlet.context-path= /
spring.thymeleaf.prefix= classpath:/templates/
spring.thymeleaf.cache=false
spring.thymeleaf.suffix=.html



  1. 数据库设计
    这里就不列表格了,直接截图navicat
    在这里插入图片描述

  2. 前端页面设计
    h5页面form表单代码

	<form id="add_forum_msg"  class="row" method="post" enctype="multipart/form-data">

								<div class="form-group col-md-12">
							    <label for="type">专题</label>
							    <div class="form-controls">
							      <select name="forumType" class="form-control" id="type">
							        <option value="生活">生活</option>
							        <option value="学习">学习</option>
							        <option value="情感">情感</option>
							        <option value="经验">经验</option>
									<option value="咨询">咨询</option>
									
							      </select>
							    </div>
							  </div>
							  <div class="form-group col-md-12">
							    <label for="forumTitle">标题</label>
								  <input type="text" id="forumHost"   name="forumHost" th:value="${session.userId}"  hidden/>

								  <input type="text" class="form-control" id="forumTitle" name="forumTitle" value="" placeholder="醒目的大字号[可总结性的文字]" />
							  </div>
							  <div class="form-group col-md-12">
							    <label for="forumDetail">描述</label>
							    <textarea class="form-control" id="forumDetail" name="forumDetail" rows="5" value="" placeholder="细节阐述[建议围绕标题展开]"></textarea>
							  </div>
							  <div class="form-group col-md-12">
							    <label for="contact">备注</label>
							    <input type="text" class="form-control" id="contact" name="contact" value="" placeholder="这些内容会显示在发布的底部[推荐联系方式]" />
							  </div>

									<div class="form-group col-md-12">
										<label>图片上传</label>
										<div class="form-controls">

											<ul class="list-inline clearfix lyear-uploads-pic">
												
												<div class="upload-content">
													<h3>上传图片</h3>

													<div class="content-img">
														<ul class="content-img-list"></ul>
														<div class="file">

															<i class="mdi mdi-plus fa-3x"></i>
															<!--															<input type="file" name="imgs" accept="image/*"  multiple>-->
															<input type="file" name="imgs" accept="image/*" id="upload" multiple>

														</div>
													</div>
													<div class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
														<div class="modal-dialog modal-lg" role="document">
															<div class="modal-content">

															</div>
														</div>
													</div>
												</div>
											</ul>
										</div>
										

									</div>





									<div class="form-group col-md-12">
<!--										<button type="submit" class="btn btn-primary " id="btn-submit-upload"  >确 定</button>-->

										<button type="submit" class="btn btn-primary" id="idsub"  >确 定</button>
										<button type="button" class="btn btn-default" onclick="javascript:history.back(-1);return false;">返 回</button>
									</div>


</form>

对图片进行判断以及确认按钮添加监听(jQuery实现)

var imgFile = []; //文件流
var imgSrc = []; //图片路径
var imgName = []; //图片名字
//图片上传
$('#upload').on('change', function(e) {
    var imgSize = this.files[0].size;
    if (imgSize > 1024 * 2048 * 1) { //1M
        return alert("上传图片不能超过2M");
    };
    if (this.files[0].type != 'image/png' && this.files[0].type != 'image/jpeg' && this.files[0].type != 'image/gif') {
        return alert("图片上传格式不正确");
    }

    var imgBox = '.content-img-list';
    var fileList = this.files;
    for (var i = 0; i < fileList.length; i++) {
        var imgSrcI = getObjectURL(fileList[i]);
        imgName.push(fileList[i].name);
        imgSrc.push(imgSrcI);
        imgFile.push(fileList[i]);

        console.log("#upload------>"+imgName+imgFile);
    }
    addNewContent(imgBox);
    this.value = null; //上传相同图片
});
$("#idsub").on('click', function() {
		console.log("js——————->#idsub的点击事件被执行");
		var formData = new FormData($("#add_forum_msg")[0]);


		$.each(imgFile, function (i, file) {
			// formFile.append('myFile[]', file);
			formData.append('myFile[]', file);
			console.log("myfile[]-------->"+file);
		});

		$.ajax({

	    type : "POST",
	    url : "/user/launch_oneForum" , //变量
		//方法1:将form表单数据序列化
		// data : $('#add_forum_msg').serializeArray(),

		data: formData,
		async : false, // 为true会继续执行ajax后面的脚本,直到服务器端返回数据后,触发$.ajax里的success方法,这时候执行的是两个线程。
		cache: false,
		processData : false,  //必须false才会避开jQuery对 formdata 的默认处理
		contentType : false,  //必须false才会自动加上正确的Content-Type
		error : function() {//请求失败处理函数
	      alert("原始数据错误!");
	      console.log($('#add_forum_msg').serializeArray());

		},
	    success :function(data) {//result结果
			console.log("------>data:"+data);

			if (data.msg == "success") {
				$.confirm({
					title: 'SUCCESS!',
					content: '发布成功!',
					type: 'green',
					buttons: {
						omg: {
							text: '好的',
							btnClass: 'btn-green',

						},
						close: {
							text: '关闭',
						}
					}
				});

			}
			if (data.msg == "addExcept") {
				$.confirm({
					title: 'ADDEXCEPTION',
					content: '发布失败!',
					type: 'danger',
					buttons: {
						omg: {
							text: '好的',
							btnClass: 'btn-red',

						},
						close: {
							text: '关闭',
						}
					}
				});
			}
			if (data.msg == "uploadExcept") {
				$.confirm({
					title: 'UPLOADEXCEPTION',
					content: '图片上传失败!',
					type: 'warning',
					buttons: {
						omg: {
							text: '好的',
							btnClass: 'btn-red',

						},
						close: {
							text: '关闭',
						}
					}
				});
			}
		}


		})

		return false;
	});

  1. 后台功能实现
    实体类ForumLaunch,如下,get,set方法未码出。
@Entity
@Table(name="forum_launch_info")
public class ForumLaunch {
    @Id
    private String forumId;

    private String forumTitle;

    private String forumType;

    private String forumDetail;

    private String forumImg;
    @Column(name="launch_time")
    private Date launchTime;

    private String contact;

    private String launchCheck;

    private String forumHost;
    }

实体类的封装类ForumLaunchFlag如下,get,set方法未码出。

@Configuration
public class ForumLaunchFlag {

    private List<ForumLaunch>forumLaunchList;//存储信息
    private String flag;//标识
    private Page<ForumLaunch>forumLaunchPage;//分页查询
}

repository类 ForumLaunchRepository 代码如下

public interface ForumLaunchRepository extends JpaRepository<ForumLaunch,String>, JpaSpecificationExecutor<ForumLaunch> {
//这里可以自己写方法
}

service 层 ForumService代码如下:

public interface ForumService {

    /*论坛发布的方法,
    返回值为ForumLaunchFlag类型
    */
    ForumLaunchFlag launchOneService(ForumLaunch forumLaunch);//发布一则论坛

实现接口类 ForumServiceImpl代码如下:

@Service("ForumService")
public class ForumServiceImpl implements ForumService {
    @Resource
    private ForumLaunchRepository forumLaunchRepository;
    @Resource
    private ForumLaunchFlag forumLaunchFlag;
 public ForumLaunchFlag launchOneService(ForumLaunch forumLaunch) {

        forumLaunchFlag.setFlag(FlagMsg.Success());

        try{
            forumLaunchRepository.save(forumLaunch);
        }catch (Exception e){
            System.out.println("ForumService:add------>"+e);
            forumLaunchFlag.setFlag(FlagMsg.ExceptionError());
        }

        return forumLaunchFlag;
    }

controller层 forumController 代码如下:

@Controller
@RequestMapping("/user")
public class ForumController {

    private ForumLaunchFlag forumLaunchFlag;
     @Resource
    private ForumService forumService;

 /*页面点击事件响应:
    位置:论坛页面左侧边栏---发布我的
    结果:跳转到论坛“发布我的”的页面*/
    @RequestMapping("/forum_launch.html")
    public ModelAndView a_click_forumLunch(){
        ModelAndView mav = new ModelAndView();
        mav.setViewName("forum_launch");

        return mav;
    }
 /*发布一则论坛
    返回判断标识
    */
    @ResponseBody   //用于返回json数据,用ajax时
    @PostMapping("/launch_oneForum")
    public Map<String, Object> but_launch_one_forum(ForumLaunch forumLaunch,@RequestParam("myFile[]") MultipartFile[] files,HttpServletRequest request){
        String msg="";
        //得到的whologin是登录状态下的存入session类的“userId”键值对的值
        String whoLogin = (String)request.getSession().getAttribute("userId");

        String putInMySql = "";

        int length = files.length;
        System.out.println("controller---length:"+length);
        for (MultipartFile file : files) {    //循环保存文件

            String fileName = file.getOriginalFilename();
            String suffixName = fileName.substring(fileName.lastIndexOf("."));
            //重新生成文件名
            fileName = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date()) + UUID.randomUUID() + suffixName;

            putInMySql += "/photos/"+fileName+";";

            // 存放上传图片的文件夹
            File fileDir = UploadUtils.getImgDirFile();
            System.out.println(fileDir.getAbsolutePath());
            try {
                // 构建真实的文件路径
                File newFile = new File(fileDir.getAbsolutePath() + File.separator + fileName);
                System.out.println(newFile.getAbsolutePath());

                // 上传图片到 -》 “绝对路径”
                file.transferTo(newFile);
            } catch (IOException e) {
                e.printStackTrace();
                msg = "uploadExcept";
            }
        }
	    //forumLaunch.setForumId(AutoGenerateId.getOrderId("many"));//主键生成工具下生成的,测试可自己输入字符串
	    forumLaunch.setForumId("1");
        forumLaunch.setForumHost("蓝鸢尾");
        forumLaunch.setForumImg(putInMySql);
        forumLaunch.setLaunchTime(new Date());

        //写入数据库
        forumLaunchFlag = forumService.launchOneService(forumLaunch);
        //判断
        if (FlagMsg.Success() == forumLaunchFlag.getFlag()) {
            msg = "success";
        } else {
            msg = "addExcept";
        }

        Map<String,Object> map = new HashMap<>();
        map.put("msg",msg);
        return map;
    }

总结

spring boot是一个很好用的web开发框架,是一个基于注解的开发模式,想要学的更深入就需要对它的注解更加熟练。没事看看它的接口,学习其它大佬的代码编写思想。
当然,我也是个spring boot的初学者,代码编写还不够规范,开发能力也急需加强,开发小白,不请自来,希望能够共同探讨问题,也会持续进行项目开发笔记更新。
代码是从工程下面截下来的,有差错欢迎留言指正,没有写过多的说明。
附录:用到的一些自定义工具类:
FlagMsg 代码如下:

@Configuration
public  class FlagMsg {//标识字符串
    public static  String pwdNotMatch(){
        return "两次密码输入不一致";
    }
    public static  String pwdWrong(){
        return "密码错误";
    }
    public static  String IsNotExist(){
        return "不存在";
    }
    public static  String IsExist(){
        return "已存在";
    }
    public static  String ExceptionError(){
        return "意料之外的错误";
    }
    public static  String IsNull(){
        return "为空";
    }
    public static  String Success(){
        return "通过的";
    }
    public static  String Error(){
        return "失败的";
    }

}

AutoGenerateId 代码如下:


```java
/**
 * 按照时间理论生成唯一属性ID
 * 方法getOrderId默认生成的是时间加3位随机数数的号码,即:
 * yyyyMMddHHmmssXXX
 */

public class AutoGenerateId {

        /**
         * 20位末尾的数字id
         */
        public static  int Guid=100;
        private static AutoGenerateId GetTime;

        public static String getOrderId(String ManyOrBitAndDefaultBit) {//默认生成的是时间加3位随机数数的号码

            GetTime.Guid+=1;

            long now = System.currentTimeMillis();

            //获取时间
            SimpleDateFormat dateFormat=new SimpleDateFormat("yyyyMMddHHmmss");
            //获取时间戳
            String time=dateFormat.format(now);
            String info=now+"";
            //获取三位随机数
            //int ran=(int) ((Math.random()*9+1)*100);
            //要是一段时间内的数据连过大会有重复的情况,所以做以下修改
            int ran=0;
            if(GetTime.Guid>999){
                GetTime.Guid=100;
            }
            ran=GetTime.Guid;

            if("many"==ManyOrBitAndDefaultBit){
                return time+ran+info.substring(2, info.length());
            }

            return time+ran;
        }




}

UploadUtils 代码如下:

public class UploadUtils {

    // 项目根路径下的目录  -- SpringBoot static 目录相当于是根路径下(SpringBoot 默认)
    public final static String IMG_PATH_PREFIX = "static/photos";

    public static File getImgDirFile(){

        // 构建上传文件的存放 "文件夹" 路径
        String fileDirPath = new String("src/main/resources/" + IMG_PATH_PREFIX);

        File fileDir = new File(fileDirPath);
        if(!fileDir.exists()){
            // 递归生成文件夹
            fileDir.mkdirs();
        }
        return fileDir;
    }


}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值