SpringBoot-06:SpringBoot增删改查一套完整的考试案例
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------
本此博客记录一套考试题,随后我把项目以及题目发到github上,简单的说一下springboot的开发
本此考试题用Spring+SpringMVC+MyBatis+SpringBoot+MySQL+Druid+.yml配置文件+thymeleaf模板引擎
我会把大量源码放上来,以及整合需要的注意点,大家可以一会去github上下载观看
项目概览:
一,jar包,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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>z05springbootmyself_exam</artifactId> <packaging>war</packaging> <name>z05springbootmyself_exam Maven Webapp</name> <!-- FIXME change it to the project's website --> <url>http://www.example.com</url> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </dependency> <!-- 核心依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 可以实现热部署,在IDEA上实现热部署还需一些额外的配置,请查阅资料 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> <scope>runtime</scope> </dependency> <!-- JDBC for mysql --> <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> <!-- mybatis --> <!--mybatis--> <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.1</version> </dependency> <!--fastJson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.12</version> </dependency> <!--druid--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.18</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.1</version> </dependency> <!--thymeleaf 新的模板引擎,比jsp要出色--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!--jdbc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <!-- 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>1.2.3</version> </dependency> </dependencies> <build> <finalName>z05springbootmyself_exam</finalName> <!--maven插件--> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> <!--xml配置,此是为了将来整合Hibernate或者mybatis 默认没有需要配置 --> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> </resource> </resources> </build> </project>
注意点:如果自己工程不是通过官网骨架创建,自己粘的话,小心粘了俩个parent节点,他不会报错,但是在后续就不会下载jar包了
二,数据库脚本,我给一份
DROP TABLE IF EXISTS `air_quality_index`; CREATE TABLE `air_quality_index` ( `id` int(11) NOT NULL AUTO_INCREMENT, `district` varchar(255) NOT NULL, `monitorTime` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP, `pm10` int(255) NOT NULL, `pm25` int(255) NOT NULL, `monitoringStation` varchar(255) NOT NULL, `createDate` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of air_quality_index -- ---------------------------- INSERT INTO `air_quality_index` VALUES ('1', '西城区', '2018-05-22 09:34:05', '243', '176', '灵境胡同监测站', '2018-05-22 10:57:21'); INSERT INTO `air_quality_index` VALUES ('2', '东城区', '2018-05-22 09:34:05', '27', '33', '东四监测站', '2018-05-22 09:34:35'); INSERT INTO `air_quality_index` VALUES ('3', '海淀区', '2018-05-22 09:34:05', '21', '30', '航天桥监测站', '2018-05-22 09:34:35'); INSERT INTO `air_quality_index` VALUES ('4', '丰台区', '2018-05-22 09:34:05', '24333', '17', '七里庄监测站', '2018-05-22 10:55:20'); INSERT INTO `air_quality_index` VALUES ('5', '西城区', '2018-05-22 09:58:03', '100', '1', '北京某地', '2018-06-22 16:41:51'); INSERT INTO `air_quality_index` VALUES ('6', '东城区', '2018-05-22 09:58:03', '22', '22', '山东某地222333', '2018-05-22 10:54:36'); INSERT INTO `air_quality_index` VALUES ('7', '西城区', '2018-05-22 09:58:03', '22', '22', '天津某地', '2018-05-22 10:57:41'); INSERT INTO `air_quality_index` VALUES ('8', '西城区', '2018-05-22 09:58:03', '122', '232', '山东222', '2018-05-22 10:58:59'); INSERT INTO `air_quality_index` VALUES ('9', '0', '2018-05-22 09:58:03', '22', '22', '北京某地', '2018-05-22 11:26:42'); INSERT INTO `air_quality_index` VALUES ('10', '西城区', '2018-05-22 09:58:03', '22', '22', '天津某地', '2018-06-22 16:42:17'); INSERT INTO `air_quality_index` VALUES ('11', '西城区', '2018-05-22 09:58:03', '1', '22', '灵境胡同监测站', '2018-06-22 16:42:50');
三,application.yml的配置
server: #端口号 port: 8080 spring: #模板引擎 thymeleaf: prefix: classpath:/templates/ mode: HTML5 cache: false #阿里的druid datasource: name: test url: jdbc:mysql:///exam_air username: root password: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver filters: stat maxActive: 20 initialSize: 1 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20 mybatis: #映射的xml文件 mapper-locations: classpath:mapping/*.xml #别名 type-aliases-package: com.happy.entity
注意点:他是一种新的模板,yml不可以使用制表符TAB,它通过空格表示层级关系,同样的节点反复出现会有问题
我在里面配置了tomcat的端口,druid的数据源,以及mybatis的部分配置
四,项目骨架预览
五,thymeleaf模板的创建,他是以.html后缀名结尾的文件
1.主页面:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <link rel="stylesheet" th:href="@{/css/bootstrap.min.css}"> <!--引入js的时候切记 不需要加 springboot的默认文件名称--> <script type="text/javascript" th:src="@{/js/jquery-1.8.3.min.js}"></script> <script type="text/javascript" th:src="@{/js/jquery.pagination.js}"></script> <script type="text/javascript" th:src="@{/js/bootstrap-modal.js}"></script> <script type="text/javascript"> window.onload=function () { $("tr:odd").css("background","pink"); } </script> <title>Title</title> <style type="text/css"> table{ border-collapse: collapse; } </style> </head> <body> <table width="70%" border="1" align="center" id="list"> <caption><h1 style="height: 50px;line-height5:0px;border: 1px">空气质量检测信息库</h1> 按区域查询 <select name="district" id="ourSelect"> <option value="0">不限</option> <option value="西城区">西城区</option> <option value="东城区">东城区</option> <option value="海淀区">海淀区</option> <option value="丰台区">丰台区</option> </select> <input type="button" onclick="myselect()" value="查找"/> <a href="/goAddPage">添加空气质量信息</a> </caption> <thead> <tr class="t_head"> <th>序号</th> <th>区域</th> <th>检测时间</th> <th>PM10数据</th> <th>PM2.5数据局</th> <th>监测站</th> </tr> </thead> <tbody id="list-content"> </tbody> </table> <div class="pagination" id="pagination"></div> <div id="isOK"></div> <script type="text/javascript"> $(function () { $("#update").hide(); }) load(); //默认初始化 /*点击查询的触发事件*/ function load() { $.ajax({ url: "/findAll", type: "post", success: function (data) { //清空数据 $("#list-content").html(''); //追加数据 $.each(data, function (i, dom) { //一个dom就是一个新闻对象 $("#list-content").append("<tr><td>"+ dom.id + "</td><td><a onclick='update("+dom.id+")'>"+dom.district+"</a>" + "</td><td>" + dom.monitorTime + "</td><td>" + dom.pm10 + "</td><td >" + dom.pm25 + "</td><td>"+ dom.monitoringStation+"</td></tr>"); }); $("tr:odd").css("background","pink"); } }); }; function myselect() { $.ajax({ url: "/selectByCondition", type: "post", data:{"district":$("#ourSelect").val()}, success: function (data) { //清空数据 $("#list-content").html(''); //追加数据 $.each(data, function (i, dom) { //一个dom就是一个新闻对象 $("#list-content").append("<tr><td>"+ dom.id + "</td><td><a onclick='update("+dom.id+")'>"+dom.district+"</a>" + "</td><td>" + dom.monitorTime + "</td><td>" + dom.pm10 + "</td><td >" + dom.pm25 + "</td><td>"+ dom.monitoringStation+"</td></tr>"); }); $("tr:odd").css("background","pink"); } }); }; function update(id) { $("#update").show(); $("#list").hide(); $.ajax({ url:'/goUpdatePage', type:"post", data:{"id":id}, success:function(data){ $("[name=id]").val(data.id); $("[name=district]").val(data.district); $("[name=monitorTime]").val(data.monitorTime); $("[name=pm10]").val(data.pm10); $("[name=pm25]").val(data.pm25); $("[name=monitoringStation]").val(data.monitoringStation); } }); } </script> <center> <div id="update"> <h2>空气质量信息维护页面</h2> <form method="post" action="/updateAir"> <input type="hidden" name="id"/> <p>监测区域: <select name="district"> <option value="0">不限</option> <option value="西城区">西城区</option> <option value="东城区">东城区</option> <option value="海淀区">海淀区</option> <option value="丰台区">丰台区</option> </select></p> <p>监测日期: <input type="text" name="monitorTime" /></p> <p>PM10值: <input type="text" name="pm10" /></p> <p>PM2.5值: <input type="text" name="pm25" /></p> <p>监测站: <input type="text" name="monitoringStation"/></p> <input type="submit" value="更新"/> <input type="button" onclick="javascript:$('#list').show();$('#update').hide()" value="返回"/> </form> </div> </center> </body> </html>
main.html
2.添加页面:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" th:src="@{/js/jquery-1.8.3.min.js}"></script> <style type="text/css"> #box{ width:30%; margin: 0px auto; } </style> <script type="text/javascript"> function checkInfo() { var district=$("[name=district]").val(); var monitorTime=$("[name=monitorTime]").val(); var pm10temp=$("[name=pm10]").val(); var pm10=parseInt(pm10temp); var pm25temp=$("[name=pm25]").val(); var pm25=parseInt(pm25temp); var monitoringStation=$("[name=monitoringStation]").val(); if(monitorTime==""){ alert("检测时间不能为空"); return false; } if(pm10temp==""){ alert("pm10的值不能为空"); return false; } var reg=/^\d+$/; if(!reg.test(pm10)){ alert('pm10只能为正整数'); return false; } if(pm25temp==""){ alert("pm25不能为空"); return false; } if(monitoringStation==""){ alert("监测站不能为空"); return false; } if(district=="不限"){ alert("监测区域不能选择不限"); return false; } return true; } $(function () { $("#form1").submit(function () { return checkInfo(); }); }); </script> </head> <body> <div id="box"> <h2>添加空气质量信息</h2> <form id="form1" method="post" action="/addAir"> <p>监测区域: <select name="district"> <option value="不限">不限</option> <option value="西城区">西城区</option> <option value="东城区">东城区</option> <option value="海淀区">海淀区</option> <option value="丰台区">丰台区</option> </select></p> <p>监测日期: <input type="text"name="monitorTime"/></p> <p>PM10值: <input type="text"name="pm10"/></p> <p>PM2.5值: <input type="text"name="pm25"/></p> <p>监测站: <input type="text"name="monitoringStation"/></p> <input type="submit" value="提交"/> </form> </div> <script type="text/javascript"> </script> </body> </html>
3.修改页面:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"> <head> <meta charset="UTF-8"> <title>Title</title> <script type="text/javascript" th:src="@{/js/jquery-1.8.3.min.js}"></script> <style type="text/css"> #box{ width:30%; margin: 0px auto; } </style> <script type="text/javascript"> </script> </head> <body> <div id="box"> <h2>空气质量信息维护页面</h2> <form method="post" action="/updateAir"> <input type="hidden" name="id" value="${air.id}"/> <p>监测区域: <select name="district"> <option value="0">不限</option> <option value="西城区">西城区</option> <option value="东城区">东城区</option> <option value="海淀区">海淀区</option> <option value="丰台区">丰台区</option> </select></p> <p>监测日期: <input type="text"value="${air.monitorTime}"/></p> <p>PM10值: <input type="text"value="${air.pm10}"/></p> <p>PM2.5值: <input type="text"value="${air.pm25}"/></p> <p>监测站: <input type="text"value="${air.monitoringStation}"/></p> <input type="submit" value="更新"/> <input type="button" value="返回"/> </form> </div> <script type="text/javascript"> </script> </body> </html>
注意点:他是一种新的模板,与jsp写法有不同,展示数据的方式,引用js,css都不太一样,也不同与EL,JSTL,需要摸索
它的核心th
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
六,实体类
package cn.happy.entity; import cn.happy.util.JsonDateSerializer; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import org.springframework.format.annotation.DateTimeFormat; import java.util.Date; public class AirModel { private Integer id; private String district; @DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") @JsonSerialize(using = JsonDateSerializer.class) /*处理日期格式*/ private Date monitorTime; private Integer pm10; private Integer pm25; private String monitoringStation; private Date createDate; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getDistrict() { return district; } public void setDistrict(String district) { this.district = district; } public Date getMonitorTime() { return monitorTime; } public void setMonitorTime(Date monitorTime) { this.monitorTime = monitorTime; } public Integer getPm10() { return pm10; } public void setPm10(Integer pm10) { this.pm10 = pm10; } public Integer getPm25() { return pm25; } public void setPm25(Integer pm25) { this.pm25 = pm25; } public String getMonitoringStation() { return monitoringStation; } public void setMonitoringStation(String monitoringStation) { this.monitoringStation = monitoringStation; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } }
注意点:日期类型处理格式
@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss") @JsonSerialize(using = JsonDateSerializer.class) /*处理日期格式*/ private Date monitorTime;
七,工具类---就是处理日期格式的那个工具类
package cn.happy.util; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class JsonDateSerializer extends JsonSerializer<Date> { private SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Override public void serialize(Date date, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException { String value = dateFormat.format(date); gen.writeString(value); } }
八,Dao层
1.接口:
package cn.happy.mapper; import cn.happy.entity.AirModel; import java.util.List; import java.util.Map; public interface IAirDAO { //查询所有 public List<AirModel> findAll() throws Exception; //添加 public int addAir(AirModel model) throws Exception; //修改 public int updateAir(AirModel model) throws Exception; //按条件查询 public List<AirModel> findAirByCondition(Map<String,Object> map) throws Exception; //根据编号查询对象的方法 public AirModel selectOneById(Integer id) throws Exception; }
注意:他是一个普通的接口,没有注解是因为我在别处配置了一道,在yml有配置,在启动的那个main方法上面也有一道配置
2.dao层的xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="cn.happy.mapper.IAirDAO" > <!--01.查询所有记录--> <select id="findAll" resultType="cn.happy.entity.AirModel"> select * from air_quality_index </select> <insert id="addAir"> insert into air_quality_index(district,monitorTime,pm10,pm25,monitoringStation,createDate) values(#{district},#{monitorTime},#{pm10},#{pm25},#{monitoringStation},now()) </insert> <!--修改--> <update id="updateAir"> update air_quality_index set district=#{district},monitorTime=#{monitorTime},pm10=#{pm10},pm25=#{pm25},monitoringStation=#{monitoringStation},createDate=now() where id=#{id} </update> <!--按条件查询--> <select id="findAirByCondition" resultType="cn.happy.entity.AirModel"> select * from air_quality_index <where> <if test='district!="0"'> district=#{district} </if> </where> </select> <!--查询单项--> <select id="selectOneById" resultType="cn.happy.entity.AirModel"> select * from air_quality_index where id=#{id} </select> </mapper>
注意:命名空间,别名
还有那个智能标签if test里面的写法
直接传的String类型他会报错,说没有getString的方法,所以用map往里传参数
假如test='address!=0',他会报错,说不可以转换为数字,故写为test='address!="0"'即可
九,service层:
1.接口:
package cn.happy.service; import cn.happy.entity.AirModel; import java.util.List; public interface IAirService { //查询所有 public List<AirModel> findAll() throws Exception; //添加 public int addAir(AirModel model) throws Exception; //修改 public int updateAir(AirModel model) throws Exception; //按条件查询 public List<AirModel> findAirByCondition(String district) throws Exception; //根据编号查询对象的方法 public AirModel selectOneById(Integer id) throws Exception; }
2.实现类:
package cn.happy.service.impl; import cn.happy.entity.AirModel; import cn.happy.mapper.IAirDAO; import cn.happy.service.IAirService; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; import java.util.Map; @Service("airService") public class AirServiceImpl implements IAirService { @Resource(name = "IAirDAO") private IAirDAO dao; @Override public List<AirModel> findAll() throws Exception { return dao.findAll(); } @Override @Transactional public int addAir(AirModel model) { try { return dao.addAir(model); } catch (Exception e) { e.printStackTrace(); return 0; } } @Override public int updateAir(AirModel model) throws Exception { return dao.updateAir(model); } @Override public List<AirModel> findAirByCondition(String district) throws Exception { Map<String,Object> map=new HashMap<String,Object>(); map.put("district",district); return dao.findAirByCondition(map); } @Override public AirModel selectOneById(Integer id) throws Exception { return dao.selectOneById(id); } }
注意点:和普通的SSM注解开发没有什么太大的区别,值得注意的是事务的运用,需要在main那边开启一道配置
十,controller层:
package cn.happy.controller; import cn.happy.entity.AirModel; import cn.happy.service.IAirService; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.Resource; import javax.validation.constraints.FutureOrPresent; import java.util.List; @Controller public class FirstController { //植入Service @Resource(name = "airService") private IAirService myAirService; @RequestMapping("/goHome") public String getHome(){ return "main"; } @RequestMapping("/findAll") @ResponseBody public Object findAll() throws Exception { List<AirModel> list = myAirService.findAll(); return list; } @RequestMapping("/goAddPage") public String goAddPage(){ return "addAir"; } //添加数据 @RequestMapping("/addAir") public String addAir(AirModel model, Model modelData) throws Exception { int count = myAirService.addAir(model); if (count>0){ return "redirect:goHome"; }else{ modelData.addAttribute("erroMsg","添加失败"); return "redirect:goHome"; } } @RequestMapping("/goUpdatePage") @ResponseBody public Object goUpdatePage(int id) throws Exception { AirModel air = myAirService.selectOneById(id); return air; } @RequestMapping("/updateAir") public String updateAir(AirModel model) throws Exception { int count = myAirService.updateAir(model); return "redirect:goHome"; } //按条件查询 @RequestMapping("selectByCondition") @ResponseBody public Object selectByCondition(String district) throws Exception { List<AirModel> list = myAirService.findAirByCondition(district); return list; } }
普普通通,做过SSM的发现,没什么不同
十一,SpringBoot核心启动类的配置
package cn.happy; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication //扫描mapper映射 @MapperScan("cn.happy.*") /*开启事务*/ @EnableTransactionManagement public class ExamApplication { public static void main(String[] args) { SpringApplication.run(ExamApplication.class, args); } }
注意点:开启事务和mybatis的扫描
十二,可以启动项目和调试了
注意:
我没仔细讲js,css,logback,logback就普通配置,无关紧要,css,js放在static下面即可,引入方式可以参考案例,我引用了一个bootstrap的js,这无关紧要,不影响,只需要jquery即可
作者:晨曦Dawn
转载请注明出处,地址:https://www.cnblogs.com/DawnCHENXI/p/9221212.html
github地址:(一会上传完成之后,发出来)
如果上方博客有错误或者疑惑,请指出,感激不敬!!!!!!!!!!!!!!