文章目录
一、项目介绍
这是个简单的项目,大概功能就是一个简单的记事本吧,发布文章,查看文章,登录注册。
项目仓库链接:仓库
接下来的文章最好是参考仓库里的代码来读,不要跟着文章敲。文章里面不会手把手带你敲的。
二、需求设计
就是登录注册,文章增删改查吧。
三、数据库设计
很简单得设计了一下,就三张表。一张用户表,一张分类表,一张文章表。
用户表:
id,username,password,name,email,role
分类表:
id,name
文章表:
id,title,content,category_id,user_id
四、项目构建
项目技术选型:
我们这个项目太简单了,就用用SpringBoot来构建项目。
构建项目说明:
项目架构
我们的项目主要就是3个模块,
common公用模块,公用的东西都在里面。(common模块的东西是照抄苍穹外卖的)
pojo数据模块,很多数据相关的东西就在这里面,比如说数据实体类什么的。
server服务模块,这个模块就是负责提供各种服务了。
maven
maven是一款为Java项目提供构建和依赖管理支持的工具。
我们的项目会有很多依赖,这些依赖就得依靠maven了。
而依赖的东西添加的话就可以在pom.xml文件里面加。
MySQL
关系型数据库。所谓的数据持久化,就是将数据存起来,一般就是将数据存在本地。我们前面的数据库设计就是针对的MySQL数据库的设计。
Redis
非关系型数据库。KV存储结构。
五、项目开发:
项目开发思路:
一个字,抄。
要自己写项目,首先你的要去B站找个项目,先抄着,学里面的思路,跟着敲里面的代码,慢慢理解里面代码的功能,不然你想在0基础的情况下从0开始自己写个?做梦!
我前面的那个SpringBoot开发记录就是个例子。我就打算自己写,但是自己不是那么了解流程,不知道自己该做什么,导致我频频出错,项目开发进度贼迟缓,最后这个项目就逐渐搁浅了。是个败笔!
这个项目的开发是我在完成80%苍穹外卖后开始进行的。整个项目的基础文件也是拿的苍穹外卖的。
项目开发过程:
1. 导入文件包/新建项目
其实这一步很简单的,我们只需要新建一个目录(文件夹),然后用IDEA打开这个目录,再在里面复制粘贴我们的总pom.xml文件就行了。当然你也可以新建一个项目,再打开项目中的pom.xml文件,将我们的pom.xml文件的内容复制粘贴上
其实我们的这些pom.xml文件也都是苍穹外卖的,你要是照着敲过一次项目,那么你就会对这个流程有一个深刻的了解。
总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>
<parent>
<artifactId>spring-boot-starter-parent</artifactId>
<groupId>org.springframework.boot</groupId>
<version>2.7.3</version>
</parent>
<artifactId>CodeHome</artifactId>
<groupId>com.codehome</groupId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<mybatis.spring>2.2.0</mybatis.spring>
<druid>1.2.1</druid>
<pagehelper>1.3.0</pagehelper>
<lombok>1.18.20</lombok>
<fastjson>1.2.76</fastjson>
<commons.lang>2.6</commons.lang>
<aliyun.sdk.oss>3.10.2</aliyun.sdk.oss>
<knife4j>3.0.2</knife4j>
<aspectj>1.9.4</aspectj>
<jjwt>0.9.1</jjwt>
<jaxb-api>2.3.1</jaxb-api>
<poi>3.16</poi>
<spring-boot-starter-mail>2.7.3</spring-boot-starter-mail>
</properties>
<dependencyManagement>
<dependencies>
<!-- mybatis依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.spring}</version>
</dependency>
<!-- lombok依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok}</version>
</dependency>
<!-- fastjson依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson}</version>
</dependency>
<!-- commons-lang依赖 -->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons.lang}</version>
</dependency>
<!-- druid依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid}</version>
</dependency>
<!-- pagehelper依赖 -->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>${pagehelper}</version>
</dependency>
<!-- knife4j依赖 -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j}</version>
</dependency>
<!-- aspectj依赖 --><dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.sdk.oss}</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb-api}</version>
</dependency>
<!-- poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>${poi}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi}</version>
</dependency>
<!--微信支付-->
<dependency>
<groupId>com.github.wechatpay-apiv3</groupId>
<artifactId>wechatpay-apache-httpclient</artifactId>
<version>0.4.8</version>
</dependency>
<!--邮箱服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>${spring-boot-starter-mail}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2. 新建子模块:
common模块
这个模块的文件我就是照搬苍穹外卖的了。这个一个公共模块,里面的东西都还是很通用的。
pojo模块
这个模块的作用就是放项目涉及到的一些实体类。按规范来的话分为dto(查询实体类,前端传过来的数据类),entity(实体类,对应数据库里的表的实体类),vo(返回实体类,返回给前端的数据类)。按照实际情况设置。
server模块
这个就是我们的功能模块了。后端的功能就在这个模块里使用。
3. 明确需求,开始开发
按照我们前面的需求设计和数据库来整。
先看数据库:
看到数据库是这样的了,我们就可以开始写pojo模块的entity部分:
entity的类要和表里的字段对应
Category类:
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Category {
private Integer id;
private String name;
}
Paper类:
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Paper {
private Integer id;
private String title;
private String content;
private Integer categoryId;
private Long userId;
}
Users:
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Users implements Serializable {
private Long id;
private String username;
private String password;
private String name;
private String email;
private Integer role;
}
好了entity实体类就好了。
4. server模块配置,让项目跑起来:
进行配置:
- 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>
<parent>
<groupId>com.codehome</groupId>
<artifactId>CodeHome</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.codehome.server</groupId>
<artifactId>server</artifactId>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!--springboot 启动依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<!-- mysql和mybatis相关依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
</dependency>
<!--redis相关依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<optional>true</optional>
</dependency>
<!--分页查询依赖-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
</dependency>
<!--lombok相关依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--swagger相关依赖-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<!-- poi -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
</dependency>
<!--邮箱服务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>com.codehome.common</groupId>
<artifactId>common</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.codehome.pojo</groupId>
<artifactId>pojo</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
</dependencies>
<packaging>jar</packaging>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--这里写上main方法所在类的路径-->
<configuration>
<mainClass>com.codehome.server.CodeHomeApplication</mainClass>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
- yml文件配置
yml文件
# 配置项目的端口
server:
port: 8083
启动类:
@SpringBootApplication
@Slf4j
@ComponentScan(basePackages = {"com.codehome.server","com.codehome.common","com.codehome.pojo"})
public class CodeHomeApplication {
public static void main(String[] args) {
SpringApplication.run(CodeHomeApplication.class, args);
log.info("代码芝士,启动!");
}
}
配置类:
/**
* 配置类,注册web层相关组件
*/
@Configuration
@Slf4j
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
/**
* 通过knife4j生成接口文档
* @return
*/
@Bean
public Docket docket() {
ApiInfo apiInfo = new ApiInfoBuilder()
.title("代码芝士后端接口文档")
.version("1.0")
.description("代码芝士后端接口文档")
.build();
Docket docket = new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo)
.select()
.apis(RequestHandlerSelectors.basePackage("com.codehome.server.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
/**
* 设置静态资源映射
* @param registry
*/
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
/**
* 消息转换器
*/
protected void extendMessageConverters(List<HttpMessageConverter<?>> converters){
log.info("开始扩展消息转换器");
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new JacksonObjectMapper());
converters.add(0,converter);
}
}
这样基础就实现了。项目应该就可以跑起来了。
5. 项目开发开始
开发server模块。
这里就要讲一讲controller层,service层,mapper层。
controller
层:
controller层里放Controller类,通俗的来讲,Controller类的作用就是接收前端请求数据和返回信息的。
如这样:
我们在前端就可以通过向http://localhost:8083/api/paper/add
发送带参数的Post请求来实现添加文章功能。
service
层:
这个层主要负责的就是业务功能的实现了。写接口,实现接口。
mapper
层:
这个层负责操作数据库里的内容。
6. SpringBoot操作数据库配置
Spring操作数据库一般可以通过MyBatis,MyBatisPlus来。
这里我们就需要进行一些配置了。
1.在pom.xml文件里配置。前面复制粘贴已经整好了。
2.在yml文件里配置:
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/codehomebase?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root # 这里用你自己的账号密码
password: 123456
mybatis:
#mapper配置文件
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.codehome.pojo.entity
configuration:
#开启驼峰命名
map-underscore-to-camel-case: true
配置完成后,应该怎么操作数据库呢?
很简单,我们可以整一个Mapper类
像这样就可以操作数据库了。具体内容可以看后面。
7. 开发功能
首先我们再看看我们的后端需求有哪些:
一般都是先进行登录注册功能的开发,但老实说,登录注册还是有点难度的,我们就先从文章的增删改查开始开发。
8. 增删改查功能开发
首先我们就要在controller层创建对应的controller类:
然后就是在service层创建对应的service接口,以及serviceImpl实现类:
再然后就是在mapper层创建Mapper类了:
建好后,项目结构大概是这样的:
开发CategoryController类:
这里就讲个大概,详情请看源码。
在类名上面:
@RestController
是controller层必须加的注解
@RequestMapping("/***")
就是请求路径的写法
在类中各个方法上面:
@PostMapping("/add")
这个就是请求方式,有PostMapping,GetMapping,PutMapping等等
这里的@Api,@ApiOperation是接口文档相关的东西,详情可以查看
接口文档
@RestController
@RequestMapping("/api/category")
@Api(tags = "分类管理")
public class CategoryController {
@Autowired //自动装配注解
public CategoryService categoryService;
@PostMapping("/add")
@ApiOperation("保存分类数据")
public Result add(@RequestBody CategoryDTO categoryDTO){
Category category = Category.builder()
.name(categoryDTO.getName())
.build();
categoryService.save(category);
return Result.success("新建成功");
}
顺承下去,CategoryController有了后就得要去写CategoryService接口,在CategoryServiceImpl类中实现它们的功能。
大概就是这样,要注意加上@Service
注解:
然后就开发mapper层的CategoryMapper:
关于Mapper,我们可以直接在上面写注解,也可以使用xml文件
@Mapper
public interface CategoryMapper {
@Select("select * from category where name = #{name}")
Category getCategoryByName(String name);
void insert(Category category);
@Delete("delete from category where id = #{id}")
void deleteById(Integer id);
void update(Category category);
@Select("select * from category where id = #{id}")
Category getById(Integer id);
@Select("select * from category")
List<Category> list();
}
有了上面的这些解释,大家就可以想想文章增删改查怎么写了。基本上都一样,大差不差的。
9. 登录注册功能开发
这里就得要参考登陆注册功能开发
10. AOP权限校验
11.前端相关
这就很简单了,前端的内容无非就是向后端发送请求得到返回数据,更加返回的数据再在页面上进行渲染显示。
vue需要配置的部分:
vue.config.js
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
transpileDependencies: true,
lintOnSave: false,
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8083/api/',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
},
})
main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
const app = createApp(App);
const axiosInstance = axios.create({
baseURL: '/api' // 代理前缀,对应vue.config.js中的配置
});
app.config.globalProperties.$axios = axiosInstance;
app.use(store).use(router).mount('#app')
页面向后端发送请求:
// 获取数据
const getData = async () => {
const token = localStorage.getItem('token');
try {
//以下就是一个带token的请求的发送方式
const res = await axios.get('/api/category/list', {
headers: {
token: `${token}`,
}
});
console.log(paperData.value);
} catch (error) {
alert("权限不足")
}
}
六、总结
大概就是这样了。总之就是要多抄,多总结。总结下来的东西才是你自己的。加油!