项目介绍
一个博客项目
用到的技术
SpringBoot,MybatisPlus,SpringSecurity,EasyExcel,Swagger2,
Redis,Echarts,Vue,ElementUI
这里使用多模块开发,因为工作中的基本都是多模块开放
1、新建一个Mavan工程作为父模块
把src文件夹删掉父工程用不到
然后看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>
<groupId>com.zzq</groupId>
<artifactId>ZZQBlog</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>zzq-framework</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- SpringBoot的依赖配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.5.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!--fastjson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.33</version>
</dependency>
<!--jwt依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--mybatisPlus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!--阿里云OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.10.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
2、然后新建一个 公共子模块 zzq-framework
然后导入pom依赖,这里全部复制就行
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombk-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--junit-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--SpringSecurity启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--fastjson依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<!--jwt依赖-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<!--mybatisPlus依赖-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
</dependency>
<!--mysql数据库驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--阿里云OSS-->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
</dependency>
<!--AOP-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
</dependency>
</dependencies>
3、然后再新建一个创建博客后台模块 zzq-amdin,跟上边操作一样
现在目录是这样的
进入pom.xml
这里只需要依赖framework就能添加依赖
4、然后再创建一个创建博客前台模块 zzq-blog
进入到pom.xml文件,也去依赖公共子模块
然后到父工程的pom.xml文件中看,多了下面的东西
这样的好处就是,父工程打包时,他会把三个子模块一起打包起来
准备工作
创建包
创建启动类ZZQBlogAppliation
代码如下
@SpringBootApplication
public class ZZQBlogApplication {
public static void main(String[] args) {
SpringApplication.run(ZZQBlogApplication.class,args);
}
}
然后再resource中创建一个appliation.yml文件
application.yml代码
server:
port: 7777
spring:
datasource:
url: jdbc:mysql://localhost:3306/sg_blog?characterEncoding=utf-
8&serverTimezone=Asia/Shanghai
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
servlet:
multipart:
max-file-size: 2MB
max-request-size: 5MB
mybatis-plus:
configuration:
# 日志
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
global-config:
db-config:
logic-delete-field: delFlag
logic-delete-value: 1
logic-not-delete-value: 0
id-type: auto
然后这里给大家推荐一个插件,叫做easy code,大家可以安装一下
然后连接一下数据库(可以私我拿sql文件)
然后点击ok
这样就成功了
选择zzq_article这个表,右击,就会出现easycode这个选项
先简单试一下,我是这样配置的,可以跟我一样
这样就生成出来了一个实体类,是不是很方便
配置一下模版
有些东西是不用的,就都删除
添加一些lombok注解,然后ok保存
删除重新生成一下代码,就成功了
新建一个包com.zzq.domian,把entity包移动进去
创建实体类,Mapper,Service
注意思考这些文件应该写在哪个模块下?
如下:
创建Controller测试接口
注意思考这些文件应该写在哪个模块下?
进入到这个接口,会进入这个启动器,
这里我们需要注释一下
实体类上需要添加这个,然后重新启动项目
这样就测试成功了
热门文章列表
文章表分析
通过需求去分析需要有哪些字段。
需求
需要查询浏览量最高的前10篇文章的信息。要求展示文章标题和浏览量。把能让用户自己点击跳转到具
体的文章详情进行浏览。
注意:不能把草稿展示出来,不能把删除了的文章查询出来。要按照浏览量进行降序排序。
接口地址
基础版本代码实现
1、准备工作
统一响应类和响应枚举
统一响应类
package com.zzq.domain;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.zzq.enums.AppHttpCodeEnum;
import java.io.Serializable;
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> implements Serializable {
private Integer code;
private String msg;
private T data;
public ResponseResult() {
this.code = AppHttpCodeEnum.SUCCESS.getCode();
this.msg = AppHttpCodeEnum.SUCCESS.getMsg();
}
public ResponseResult(Integer code, T data) {
this.code = code;
this.data = data;
}
public ResponseResult(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public ResponseResult(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
// Static factory methods
public static ResponseResult errorResult(int code, String msg) {
ResponseResult result = new ResponseResult();
return result.error(code, msg);
}
public static ResponseResult okResult() {
return new ResponseResult();
}
public static ResponseResult okResult(int code, String msg) {
ResponseResult result = new ResponseResult();
return result.ok(code, null, msg);
}
public static ResponseResult okResult(Object data) {
ResponseResult result = setAppHttpCodeEnum(AppHttpCodeEnum.SUCCESS, AppHttpCodeEnum.SUCCESS.getMsg());
if (data != null) {
result.setData(data);
}
return result;
}
public static ResponseResult errorResult(AppHttpCodeEnum enums) {
return setAppHttpCodeEnum(enums, enums.getMsg());
}
public static ResponseResult errorResult(AppHttpCodeEnum enums, String msg) {
return setAppHttpCodeEnum(enums, msg);
}
private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums) {
return okResult(enums.getCode(), enums.getMsg());
}
private static ResponseResult setAppHttpCodeEnum(AppHttpCodeEnum enums, String msg) {
return okResult(enums.getCode(), msg);
}
// Chainable methods
public ResponseResult<?> error(Integer code, String msg) {
this.code = code;
this.msg = msg;
return this;
}
public ResponseResult<?> ok(Integer code, T data) {
this.code = code;
this.data = data;
return this;
}
public ResponseResult<?> ok(Integer code, T data, String msg) {
this.code = code;
this.data = data;
this.msg = msg;
return this;
}
public ResponseResult<?> ok(T data) {
this.data = data;
return this;
}
// Getters and Setters
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
响应枚举
package com.zzq.enums;
public enum AppHttpCodeEnum {
// 成功
SUCCESS(200,"操作成功"),
// 登录
NEED_LOGIN(401,"需要登录后操作"),
NO_OPERATOR_AUTH(403,"无权限操作"),
SYSTEM_ERROR(500,"出现错误"),
USERNAME_EXIST(501,"用户名已存在"),
PHONENUMBER_EXIST(502,"手机号已存在"), EMAIL_EXIST(503, "邮箱已存在"),
REQUIRE_USERNAME(504, "必需填写用户名"),
LOGIN_ERROR(505,"用户名或密码错误");
int code;
String msg;
AppHttpCodeEnum(int code, String errorMessage){
this.code = code;
this.msg = errorMessage;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
代码实现
在ArticleController中
@RestController
@RequestMapping("/article")
public class ArticleController {
@Autowired
private ArticleService articleService;
// @GetMapping("/list")
// public List<Article> test(){
// return articleService.list();
// }
@GetMapping("/hotArticleList")
public ResponseResult hotArticleList(){
ResponseResult result = articleService.hotArticleList();
return result;
}
}
AtricleService
public interface ArticleService extends IService<Article> {
ResponseResult hotArticleList();
}
创建VO
@Data
@NoArgsConstructor
@AllArgsConstructor
public class HotArticleVO {
private Long id;
//标题
private String title;
//访问量
private Long viewCount;
}
字面值处理
public class SystemConstants {
/**
* 文章是草稿
*/
public static final int ARTICLE_STATUS_DRAFT = 1;
/**
* 文章是正常分布状态
*/
public static final int ARTICLE_STATUS_NORMAL = 0;
}
Bean
拷贝工具类封装
public class BeanCopyUtils {
private BeanCopyUtils(){
}
public static <V> V copyBean(Object source,Class<V> clazz) {
//创建目标对象
V result = null;
try {
result = clazz.newInstance();
//实现属性copy
BeanUtils.copyProperties(source, result);
} catch (Exception e) {
e.printStackTrace();
}
//返回结果
return result;
}
public static <O,V> List<V> copyBeanList(List<O> list,Class<V> clazz){
return list.stream()
.map(o -> copyBean(o, clazz))
.collect(Collectors.toList());
}
ArticleServiceImpl
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {
@Override
public ResponseResult hotArticleList() {
//查询热门文章,封装成ResponseResult返回
LambdaQueryWrapper<Article> queryWrapper = new LambdaQueryWrapper<>();
// 必须是正式文章
queryWrapper.eq(Article::getStatus, SystemConstants.ARTICLE_STATUS_NORMAL);
// 按照浏览量进行排序
queryWrapper.orderByDesc(Article::getViewCount);
//最多只查询10条
Page<Article> page = new Page<>(1,10);
page(page,queryWrapper);
List<Article> articles = page.getRecords();
//bean拷贝
// List<HotArticleVO> articleVOS = new ArrayList<>();
//
// for (Article article : articles) {
// HotArticleVO vo = new HotArticleVO();
//
// BeanUtils.copyProperties(article,vo);
// articleVOS.add(vo);
//
// }
List<HotArticleVO> vs = BeanCopyUtils.copyBeanList(articles, HotArticleVO.class);
return ResponseResult.okResult(vs);
}
}
解决跨域问题
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 设置允许跨域的路径
.allowedOriginPatterns("*") // 设置允许跨域请求的域名
.allowCredentials(true) // 是否允许cookie
.allowedMethods("GET", "POST", "DELETE", "PUT") // 设置允许的请求方式
.allowedHeaders("*") // 设置允许的header属性
.maxAge(3600); // 跨域允许时间
}
}