目录
一、项目简介
1.1前言
致各位感兴趣了解本项目的各位人士:
因为课程要求也是自己的想法,想通过写一个博客可以方便自己回顾所学的知识。我现在要介绍的是老师在课堂所教的停车场项目。项目内容主要有SysUser(用户管理系统)、parkingLot(停车场管理)、pricingStandard(停车场收费管理)、vehicle(车辆管理)、order(订单管理)等几个类。
1.2 技术选型
下面我将分模块对本项目进行讲解
工具 | 名称 |
---|---|
开发语言 | IDEA |
语言 | JDK17、HTML、CSS、JQ |
模板引擎 | Themleaf |
数据库 | SQLyog - 64 bit |
项目框架 | SpringBoot |
ORD | Mybatis plus |
项目构建 | Maven |
二、Mysql数据库搭建准备
我这里一共有五张表分别是:Vehicle(车辆)、PricingStandard(收费标准)、ParkingLot(停车场)、Order(订单)、SysUser(系统用户)。
他们之间的联系下图可以明确的解释说明。
建立外键的时候遇到了个小bug,错误提示是:
错误代码:1452
Cannot add or update a child row: a foreign key constraint fails (`2022soft`.`#sql-1480_170`, CONSTRAINT `pricing_standard_id` FOREIGN KEY (`pricing_standard_id`) REFERENCES `pricing_standard` (`id`))
发现1452的错误主要原因就是:有外键的子表对应的主表中没有数据。
原来是我主表没有子表的写有数据,产生了bug无法建立外键。给他添加了相对于的数据之后就好了。
三、IDEA环境搭建准备
pom.xml文件依赖注入如下:
导入项目所需的依赖坐标等待idea自动下载jar包即可。
<?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>3.1.4</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>parkingMIS</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>parkingMIS</name>
<description>parkingMIS</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--注入mysql依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.0.33</version>
</dependency>
<!--注入mybatis plus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
<!-- 注入thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 注入bootstrap依赖-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.3.0</version>
</dependency>
<!-- 注入jq依赖-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.4</version>
</dependency>
<!-- 注入webjars依赖-->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<!-- 注入mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>3.0.2</version>
</dependency>
<!-- 注入mysql依赖-->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>10.1.13</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
我们可以使用yml格式的配置文件(更简洁)和properties文件功能相同,编写格式不同。
四、后端代码
- entity:实体层,实现对库映射,代码优先。
- mapper(DAO层):持久化层(对DB操作),对库的操作,调用resources.mapper
- resources.mapper:Dao层与mapper映射器的映射,绑定(SQL)对象
- service:功能实现,类似密码加密——处理业务逻辑,调用mapper接口
- controller:处理用户请求(GET/POST/PUT/DELETE),调用service
vehicle的实体类:
注意事项:创建数据库时要看好自己在实体类对应的字段。
@TableName:在MyBatis框架中,
@TableName
注解用于指定映射的数据库表名。在这个例子中,@TableName("vehicle")
表示该注解所在的类将映射到数据库中的"vehicle"表。这是一种常见的做法,用于在Java代码和数据库表之间建立映射关系。@TableId(type = IdType.AUTO):在MyBatis框架中,
@TableId(type = IdType.AUTO)
注解用于指定主键列的自动生成策略。IdType.AUTO
表示根据数据库的类型自动选择生成策略,具体取决于数据库的约束和配置。@TableField:在MyBatis框架中,
@TableField
注解用于指定映射的数据库字段名。它通常与@TableName
注解一起使用,以明确指定表名和字段名。
@TableName("vehicle")
/*车辆实体*/
@Data
public class Vehicle {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("licence_Plate")
private String licencePlate;//车牌号
private String picUrl;//车辆入场照片存储位置
@TableField("is_Active")
private boolean isActive;//入场、离场标记,true:入场,否则是离场
@TableField("parking_lot_id")
private ParkingLot parkingLot;//关联的停车场
public Vehicle(){
this.isActive=true;
};
public Vehicle(Vehicle entity){
this.id=entity.id;
this.licencePlate=entity.licencePlate;
this.isActive=entity.isActive;
this.picUrl=entity.picUrl;
Optional.ofNullable(entity.parkingLot)
.ifPresent(x->{
this.parkingLot=new ParkingLot();
this.parkingLot.setId(x.getId());
this.parkingLot.setName(x.getName());
this.parkingLot.setVolumetric(x.getVolumetric());
});
}
}
Vehicle的持久化层:
注意事项:SQL语句一定先去MySQL使用一下,少一个空格都能让你找疯掉。
@Mapper:是MyBatis框架中定义的一个注解,用于描述数据层接口。它起到描述性作用,告诉Spring框架此接口的实现类由MyBatis负责创建,并将其实现类对象存储到Spring容器中。在实际开发中,通常使用@Mapper继承basemapper,自动实例化生成很多增删改查的
方法,不用自己去写实现类和实现方法。
@Mapper
public interface VehicleMapper extends BaseMapper<Vehicle> {
@Results({
@Result(column = "id",property = "id"),
@Result(column = "parking_lot_id",property = "parkingLot",one = @One(select = "com.example.parkingmis.mapper.ParkingLotMapper.getById"))
})
@Select("SELECT * FROM vehicle JOIN parking_Lot ON parking_Lot.id=vehicle.parking_lot_id")
List<Vehicle> getAll();
@Select("SELECT * FROM vehicle JOIN parking_Lot ON parking_lot_id=parking_Lot.id where vehicle.id=#{id}")
Vehicle getById(Long id);
@Insert("insert into vehicle set licence_Plate=#{licencePlate},picUrl=#{picUrl},is_Active=#{isActive},parking_lot_id=#{parkingLot.id}")
int insert(Vehicle entity);
@Update("update vehicle set licence_Plate=#{licencePlate},picUrl=#{picUrl},is_Active=#{isActive},parking_lot_id=#{parkingLot.id} where id=#{id}")
int update(Vehicle entity);
}
Vehicle的服务层:
@Service:在Spring框架中,使用@Service注解标注的类通常包含一些业务逻辑方法,这些方法用于实现具体的业务功能。这些服务类通常会依赖其他DAO类或其他服务类,以完成数据的访问或业务逻辑的实现。
@Service
public class VehicleService extends ServiceImpl<VehicleMapper, Vehicle> {
VehicleMapper mapper;
@Autowired
public VehicleService(VehicleMapper mapper){
this.mapper=mapper;
}
public List<Vehicle> getAll(){
return mapper.getAll();
}
public Vehicle getById(Long id) {
return mapper.getById(id);
}
public boolean insert(Vehicle entity) {
int result=mapper.insert(entity);
return result>0?true:false;
}
public boolean update(Vehicle entity) {
int result=mapper.update(entity);
return result>0?true:false;
}
public boolean delete(Long id) {
int result=mapper.deleteById(id);
return result>0?true:false;
}
}
Vehicle的控制器层:
注意事项:若代码是复制前面做过的项目请一定一定要改好类名,返回的是前端链接的话先按好CTRL试试能不能跳转。
@Controller:可以标记一个类为控制器类,该类通常包含处理HTTP请求的方法。这些方法通常使用@RequestMapping注解来指定请求的URL映射和HTTP方法。当一个HTTP请求与@RequestMapping注解匹配时,相应的控制器方法将被调用,以处理该请求。
@RequestMapping:将不同的URL路径和HTTP方法映射到不同的处理方法。
@Value:需要指定注入属性的值。这个值可以是常量、环境变量、配置文件中的值等。例如,可以使用@Value("${my.property}")将配置文件中名为"my.property"的值注入到Java类中。
@Autowired:它用于自动装配bean。使用@Autowired注解可以将Spring容器中的bean自动装配到需要使用该bean的类中。
@Controller
@RequestMapping("/vehicle")
public class VehicleController {
@Value("${save.path}")
String savePath;//图片存储路径
VehicleService service;
ParkingLotService parkingLotService;
@Autowired
public VehicleController(VehicleService service,ParkingLotService parkingLotService){
this.service=service;
this.parkingLotService=parkingLotService;
}
@RequestMapping("/list")
public String list(Model model){
List<Vehicle> list=service.getAll();
model.addAttribute("list",list);//model打包成list属性完成list对象的值传递
return "/vehicle/list";
}
@RequestMapping(value="/insert")
public String insert(Model model){
model.addAttribute("vehicle",new Vehicle());
List<ParkingLot> parkingLots=parkingLotService.getAll();
model.addAttribute("parkingLots",parkingLots);
return "/vehicle/edit";
}
@RequestMapping(value="/edit/{id}")
public String edit(@PathVariable("id") Long id, Model model){
Vehicle entity=service.getById(id);
model.addAttribute("vehicle",entity);
List<ParkingLot> parkingLots=parkingLotService.getAll();
model.addAttribute("parkingLots",parkingLots);
return "/vehicle/edit";
}
@RequestMapping(value = "/detail/{id}")
public String detail(@PathVariable("id") Long id, Model model){
Vehicle entity=service.getById(id);
model.addAttribute("vehicle",entity);
return "/vehicle/detail";
}
@RequestMapping(value = "/delete/{id}")
public String delete(@PathVariable("id") Long id){
boolean result=service.delete(id);
return "redirect:/vehicle/list";
}
@RequestMapping(value = "/save",method = RequestMethod.POST)
public String save(@ModelAttribute("vehicle") Vehicle entity
, @RequestParam("isActive") boolean isActive
, @RequestParam("parkingLotId") Long parkingLotId
, @RequestParam("file")MultipartFile file)throws Exception{
entity.setActive(isActive);
ParkingLot parkingLot=parkingLotService.getById(parkingLotId);
entity.setParkingLot(parkingLot);
//上传图片文件指定目录
String fileName= System.currentTimeMillis()+"-"+file.getOriginalFilename();//生成文件名
Path saveTo= Paths.get(savePath,fileName);//设置文件存储的路径
Files.write(saveTo,file.getBytes());//完成存储文件
//存储图片url
entity.setPicUrl("/images/"+fileName);
boolean result=entity.getId()!=null?service.update(entity):service.insert(entity);
return "redirect:/vehicle/list";
}
}
五、前端代码与界面
本博客界面使用themleaf模板引擎进行页面渲染,Thymeleaf 是一个现代的服务器端Java模板引擎,适用于Web和独立环境。它被SpringBoot官方推荐使用,可以整合Spring MVC,用于Web和独立环境。Thymeleaf的主要目标是提高页面和代码的复用性,同时带来优雅自然的模板。使用Thymeleaf可以避免在页面上编写Java代码,使得Java代码和前端代码绝对的分离。
注意事项:链接js,css,jq的时候一定要检查好,稍有不慎就链接失败
以下是前端的list界面代码与效果图:
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="en">
<head>
<div th:replace="~{/fragment/header :: header}"></div>
<div th:replace="~{/fragment/header :: header-css}"></div>
<div th:replace="~{/fragment/header :: header-nav}"></div>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
<title>列表页面</title>
<link rel="stylesheet" href="/webjars/bootstrap/5.3.0/css/bootstrap.min.css" th:href="@{/webjars/bootstrap/5.3.0/css/bootstrap.min.css}">
<script src="/webjars/jquery/3.6.4/jquery.min.js" th:src="@{/webjars/jquery/3.6.4/jquery.min.js}"></script>
<script src="/webjars/bootstrap/5.3.0/js/bootstrap.min.js" th:src="@{/webjars/bootstrap/5.3.0/js/bootstrap.min.js}"></script>
<script src="/webjars/bootstrap/5.3.0/js/bootstrap.bundle.js" th:src="@{/webjars/bootstrap/5.3.0/js/bootstrap.bundle.js}"></script>
</head>
<body style="background:linear-gradient(70deg, white, pink);">
<div class="container">
<a th:href="@{/vehicle/insert}" class="btn btn-outline-success">新增</a>
<table class="table table-striped">
<thead>
<tr>
<td>序号</td>
<td>车牌号</td>
<td>车辆入场照片存储位置</td>
<td>入场、离场标记</td>
<td>停车场</td>
<td>功能</td>
</tr>
</thead>
<tbody>
<tr th:each="vehicle: ${list}">
<td th:text="${vehicle.id}"></td>
<td th:text="${vehicle.licencePlate}"></td>
<td th:text="${vehicle.picUrl}"></td>
<td th:text="${vehicle.isActive()}"></td>
<td th:text="${vehicle.parkingLot}"></td>
<td>
<a th:href="@{/vehicle/edit/{id}(id=${vehicle.id})}" class="btn btn-outline-info">修改</a>
<a th:href="@{/vehicle/detail/{id}(id=${vehicle.id})}" class="btn btn-outline-warning">详情信息</a>
<a th:href="@{/vehicle/delete/{id}(id=${vehicle.id})}" class="btn btn-outline-danger">删除</a>
</td>
</tr>
</tbody>
</table>
</div>
<div th:replace="~{/fragment/header :: header-js}"></div>
<div th:replace="~{/fragment/footer :: footer}"></div>
</body>
</html>
*************************************************************************************************************
以下是前端的edit界面代码与效果图:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>修改or插入</title>
<div th:replace="~{/fragment/header :: header}"></div>
<div th:replace="~{/fragment/header :: header-css}"></div>
<div th:replace="~{/fragment/header :: header-nav}"></div>
</head>
<body>
<form action="/vehicle/save" th:object="${vehicle}" method="post" enctype="multipart/form-data">
<input th:type="hidden" th:field="*{id}">
<fieldset>
<div class="col-auto">
<label for="licencePlate" class="col-form-label">车牌号:</label>
<input th:field="*{licencePlate}" type="text" class="form-control" id="licencePlate">
</div>
<div class="col-auto">
<label for="picUrl" class="col-form-label">车牌图片:</label>
<img th:src="*{picUrl}" class="figure-img img-fluid rounded" alt="车牌图片" id="picUrl">
<input type="file" name="file">
</div>
<div class="col-auto">
<label class="col-form-label" for="isActive"> 入离场标记:</label>
<select class="form-control" id="isActive" name="isActive">
<option value="true">入场</option>
<option value="false">出场</option>
</select>
</div>
<div class="col-auto">
<label class="col-form-label" for="parkingLotId"> 停车场:</label>
<select class="form-control" id="parkingLotId" name="parkingLotId">
<option th:each="parkingLot:${parkingLots}" th:value="${parkingLot.id}" th:text="${parkingLot.id}">入场</option>
</select>
</div>
<button type="submit" class="btn btn-primary">提交</button>
<a th:href="@{/vehicle/list}" class="btn btn-primary">返回</a>
</fieldset>
</form>
<div th:replace="~{/fragment/header :: header-js}"></div>
<div th:replace="~{/fragment/footer :: footer}"></div>
</body>
</html>
*************************************************************************************************************
以下是前端的detail界面代码与效果图:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>详情</title>
<div th:replace="~{/fragment/header :: header}"></div>
<div th:replace="~{/fragment/header :: header-css}"></div>
<div th:replace="~{/fragment/header :: header-nav}"></div>
</head>
<body>
<h3>序号:<span th:text="${vehicle.id}"></span></h3>
<h3>车牌号:<span th:text="${vehicle.licencePlate}"></span></h3>
<h3>车辆入场照片存储位置:<img th:src="${vehicle.picUrl}"></h3>
<h3>入场、离场标记:<span th:text="${vehicle.isActive}"></span></h3>
<h3>关联的停车场:<span th:text="*{vehicle.parkingLot}"></span></h3>
<a th:href="@{/vehicle/list}" class="btn btn-primary">返回</a>
<div th:replace="~{/fragment/header :: header-js}"></div>
<div th:replace="~{/fragment/footer :: footer}"></div>
</body>
</html>
*************************************************************************************************************
以上就是我自己简单停车场车辆项目,整整写了两天,很词穷,谢谢各位同行赏脸看完~