项目说明
首页
技术栈:SpringBoot,Vue。后端功能相对简单,主要是增删查改,代码有些冗余,算是对之前SpringBoot知识的巩固。
项目配置
<?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.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dql</groupId>
<artifactId>music</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>music</name>
<description>音乐网站</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.75</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<fork>true</fork>
</configuration>
</plugin>
</plugins>
</build>
</project>
都是常用配置,使用了阿里巴巴的fastjson。
application.yml:
server:
port: 8888
spring:
datasource:
url: jdbc:mysql://localhost:3306/music?serverTimezone=Asia/Shanghai&userUnicode=true&characterEncoding=utf8&useSSL=false
username:
password:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.music.domain
使用druid连接池,限制上传文件大小50MB。
业务分析
以歌曲业务为例:新增歌曲,修改歌曲,删除歌曲,根据主键查询整个对象,查询所有歌曲,根据歌名模糊查询歌曲,根据歌手id查询歌曲。
实体类
public class Song implements Serializable {
/*主键*/
private int id;
/*歌手id*/
private int singerId;
/*歌名*/
private String name;
/*简介*/
private String introduction;
/*创建时间*/
private Date createTime;
/*更新时间*/
private Date updateTime;
/*歌曲图片*/
private String pic;
/*歌词*/
private String lyric;
/*歌曲地址*/
private String url;
}
get set以及toString方法省略,实体类实现Serializable接口是为了对实例对象的状态(State 对象属性而不包括对象方法)进行通用编码(如格式化的字节码)并保存,以保证对象的完整性和可传递性,就是为了在不同时间或不同平台的JVM之间共享实例对象。
DAO层
@Repository
public interface SongMapper {
/**
* 增加
*
* @param song
* @return
*/
public int insert(Song song);
/**
* 修改
*
* @param song
* @return
*/
public int update(Song song);
/**
* 删除
*
* @param id
* @return
*/
public int delete(Integer id);
/**
* 根据主键查询整个对象
*
* @param id
* @return
*/
public Song selectByPrimaryKey(Integer id);
/**
* 查询所有歌曲
*
* @return
*/
public List<Song> allSong();
/**
* 根据歌名模糊查询列表
*
* @param name
* @return
*/
public List<Song> songOfName(String name);
/**
* 根据歌手id查询歌曲
*
* @param singerId
* @return
*/
public List<Song> songOfSingerId(Integer singerId);
}
@Repository注解加在持久层接口上,用于将数据访问层 (DAO 层 ) 的类标识为 Spring Bean。
映射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="com.dql.music.dao.SongMapper">
<resultMap id="BaseResultMap" type="com.dql.music.domain.Song">
<id column="id" jdbcType="INTEGER" property="id"/>
<result column="singer_id" jdbcType="INTEGER" property="singerId"/>
<result column="name" jdbcType="VARCHAR" property="name"/>
<result column="url" jdbcType="VARCHAR" property="url"/>
<result column="pic" jdbcType="VARCHAR" property="pic"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="introduction" jdbcType="VARCHAR" property="introduction"/>
</resultMap>
<resultMap id="ResultMapWithBLOBs" type="com.dql.music.domain.Song" extends="BaseResultMap">
<result column="lyric" jdbcType="LONGVARCHAR" property="lyric"/>
</resultMap>
<sql id="Base_Column_List">
id,singer_id,name,url,pic,create_time,update_time,introduction
</sql>
<sql id="Blob_Column_List">
lyric,id,singer_id,name,url,pic,lyric,create_time,update_time,introduction
</sql>
<insert id="insert" parameterType="com.dql.music.domain.Song">
insert into song
<trim prefix="(" suffix=")" suffixOverrides=",">
<if test="id != null">
id,
</if>
<if test="singerId != null">
singer_Id,
</if>
<if test="name != null">
name,
</if>
<if test="url != null">
url,
</if>
<if test="pic != null">
pic,
</if>
<if test="lyric != null">
lyric,
</if>
create_time,update_time,
<if test="introduction != null">
introduction,
</if>
</trim>
<trim prefix="values (" suffix=")" suffixOverrides=",">
<if test="id != null">
#{id},
</if>
<if test="singerId != null">
#{singerId},
</if>
<if test="name != null">
#{name},
</if>
<if test="url != null">
#{url},
</if>
<if test="pic != null">
#{pic},
</if>
<if test="lyric != null">
#{lyric},
</if>
now(),now(),
<if test="introduction != null">
#{introduction},
</if>
</trim>
</insert>
<update id="update" parameterType="com.dql.music.domain.Song">
update song
<set>
<if test="singerId != null">
singer_id=#{singerId},
</if>
<if test="name != null">
name=#{name},
</if>
<if test="url != null">
url=#{url},
</if>
<if test="pic != null">
pic=#{pic},
</if>
<if test="lyric != null">
lyric=#{lyric},
</if>
update_time=now(),
<if test="introduction != null">
introduction=#{introduction},
</if>
</set>
where id=#{id}
</update>
<delete id="delete" parameterType="java.lang.Integer">
delete
from song
where id = #{id}
</delete>
<select id="selectByPrimaryKey" resultMap="ResultMapWithBLOBs" parameterType="java.lang.Integer">
select
<include refid="Blob_Column_List"></include>
from song
where id = #{id}
</select>
<select id="allSong" resultMap="ResultMapWithBLOBs">
select
<include refid="Blob_Column_List"/>
from song
</select>
<select id="songOfName" resultMap="ResultMapWithBLOBs" parameterType="java.lang.String">
select
<include refid="Blob_Column_List"/>
from song where name = #{name}
</select>
<select id="songOfSingerId" resultMap="ResultMapWithBLOBs" parameterType="java.lang.Integer">
select
<include refid="Blob_Column_List"/>
from song where singer_id = #{singerId}
</select>
</mapper>
mybatis映射文件很长,目前还没学习mybatisplus。
mysql中的extends可以避免定义多个resultMap,减少代码冗余。map中左侧为数据库中字段名,右侧为实体类中对应的属性名,注意区分下划线。
SQL 中的 trim 函数用来移除掉一个字串中的字头或字尾。最常见的用途是移除字首或字尾的空白。
写sql语句时使用test判断传参是否为空,同样需要注意数据库字段与实体类属性名的差异。
Controller层
Service层与ServiceImpl类与Mapper接口功能相似,省略。
@RestController
@RequestMapping(value = "/song")
public class SongController {
@Autowired
private SongService songService;
/**
* 添加歌曲
*
* @param request
* @param mpfile
* @return
*/
@RequestMapping(value = "/add", method = RequestMethod.POST)
public Object addSong(HttpServletRequest request, @RequestParam("file") MultipartFile mpfile) {
JSONObject jsonObject = new JSONObject();
/*获取前端传来的参数*/
String singerId = request.getParameter("singerId").trim();
String name = request.getParameter("name").trim();
String introduction = request.getParameter("introduction").trim();
String pic = "/img/songPic/1618326979608라일락.jpg";
String lyric = request.getParameter("lyric").trim();
/*上传歌曲文件*/
if (mpfile.isEmpty()) {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败");
} else {
String fileName = System.currentTimeMillis() + mpfile.getOriginalFilename();
String filePath = System.getProperty("user.dir") + System.getProperty("file.separator") + "img"
+ System.getProperty("file.separator") + "songPic";
File file = new File(filePath);
if (!file.exists()) {
file.mkdir();
} else {
/*实际的文件地址*/
File dest = new File(filePath + System.getProperty("file.separator") + fileName);
/*存储到数据库的相对文件地址*/
String storeUrlPath = "/img/songPic/" + fileName;
try {
mpfile.transferTo(dest);
Song song = new Song();
song.setSingerId(Integer.parseInt(singerId));
song.setName(name);
song.setIntroduction(introduction);
song.setLyric(lyric);
song.setUrl(storeUrlPath);
song.setPic(pic);
boolean flag = songService.insert(song);
if (flag) {
jsonObject.put(Consts.CODE, 1);
jsonObject.put(Consts.MSG, "文件上传成功");
jsonObject.put("pic", storeUrlPath);
} else {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败");
}
} catch (IOException e) {
e.printStackTrace();
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败" + e.getMessage());
} finally {
jsonObject.put("info", 0);
}
}
}
return jsonObject;
}
/**
* 更新歌曲信息
*
* @param request
* @return
*/
@RequestMapping(value = "/update", method = RequestMethod.POST)
public Object updateSong(HttpServletRequest request) {
JSONObject jsonObject = new JSONObject();
String id = request.getParameter("id").trim();
String name = request.getParameter("name").trim();
String introduction = request.getParameter("introduction").trim();
String lyric = request.getParameter("lyric").trim();
Song song = new Song();
song.setId(Integer.parseInt(id));
song.setName(name);
song.setLyric(lyric);
song.setIntroduction(introduction);
boolean flag = songService.update(song);
if (flag) {
jsonObject.put(Consts.CODE, 1);
jsonObject.put(Consts.MSG, "修改成功");
} else {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "修改失败");
}
return jsonObject;
}
/**
* 删除歌曲
*
* @param request
* @return
*/
@RequestMapping(value = "/delete", method = RequestMethod.GET)
public Object delete(HttpServletRequest request) {
// TODO: 2021/7/10 先查询到数据库中对应的文件地址,删除掉它再进行下面的代码
String id = request.getParameter("id").trim();
boolean flag = songService.delete(Integer.parseInt(id));
return flag;
}
/**
* 更新歌曲图片
*
* @param avatorFile
* @param id
* @return
*/
@RequestMapping(value = "/updateSong", method = RequestMethod.POST)
public Object updateSingerPic(@RequestParam("file") MultipartFile avatorFile, @RequestParam("id") int id) {
JSONObject jsonObject = new JSONObject();
if (avatorFile.isEmpty()) {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败");
} else {
String fileName = System.currentTimeMillis() + avatorFile.getOriginalFilename();
String filePath = System.getProperty("user.dir") + System.getProperty("file.separator") + "img"
+ System.getProperty("file.separator") + "songPic";
File file = new File(filePath);
if (!file.exists()) {
file.mkdir();
} else {
/*实际的文件地址*/
File dest = new File(filePath + System.getProperty("file.separator") + fileName);
/*存储到数据库的相对文件地址*/
String storeAvatorPath = "/img/songPic/" + fileName;
try {
avatorFile.transferTo(dest);
Song song = new Song();
song.setId(id);
song.setPic(storeAvatorPath);
boolean flag = songService.update(song);
if (flag) {
jsonObject.put(Consts.CODE, 1);
jsonObject.put(Consts.MSG, "文件上传成功");
jsonObject.put("pic", storeAvatorPath);
} else {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败");
}
} catch (IOException e) {
e.printStackTrace();
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败" + e.getMessage());
} finally {
jsonObject.put("info", 0);
}
}
}
return jsonObject;
}
/**
* 更新歌曲
*
* @param avatorFile
* @param id
* @return
*/
@RequestMapping(value = "/updateSongUrl", method = RequestMethod.POST)
public Object updateSingerUrl(@RequestParam("file") MultipartFile avatorFile, @RequestParam("id") int id) {
JSONObject jsonObject = new JSONObject();
if (avatorFile.isEmpty()) {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败");
} else {
String fileName = System.currentTimeMillis() + avatorFile.getOriginalFilename();
String filePath = System.getProperty("user.dir") + System.getProperty("file.separator") + "song";
File file = new File(filePath);
if (!file.exists()) {
file.mkdir();
} else {
/*实际的文件地址*/
File dest = new File(filePath + System.getProperty("file.separator") + fileName);
/*存储到数据库的相对文件地址*/
String storeAvatorPath = "/song/" + fileName;
try {
avatorFile.transferTo(dest);
Song song = new Song();
song.setId(id);
song.setUrl(storeAvatorPath);
boolean flag = songService.update(song);
if (flag) {
jsonObject.put(Consts.CODE, 1);
jsonObject.put(Consts.MSG, "文件上传成功");
jsonObject.put("avator", storeAvatorPath);
} else {
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败");
}
} catch (IOException e) {
e.printStackTrace();
jsonObject.put(Consts.CODE, 0);
jsonObject.put(Consts.MSG, "文件上传失败" + e.getMessage());
} finally {
jsonObject.put("info", 0);
}
}
}
return jsonObject;
}
/**
* 根据id查询歌曲
*
* @param request
* @return
*/
@RequestMapping(value = "/detail", method = RequestMethod.GET)
public Object selectByPrimaryKey(HttpServletRequest request) {
String songId = request.getParameter("songId");
return songService.songOfSingerId(Integer.parseInt(songId));
}
/**
* 根据id查询歌曲
*
* @param request
* @return
*/
@RequestMapping(value = "/songOfSongName", method = RequestMethod.GET)
public Object songOfSongName(HttpServletRequest request) {
String songName = request.getParameter("songName");
return songService.songOfName(songName);
}
}
对业务的处理放在了Controller层感觉不合适,应该放在Service实现类中。
System类中有这样的方法getProperties(),file.separator 文件分隔符(在 UNIX 系统中是“/”),用于处理在不同操作系统下分隔符不同的问题。