Spring Boot demo系列(二):简单三层架构Web应用
2021.2.24 更新
1 概述
这是Spring Boot
的第二个Demo
,一个只有三层架构的极简Web
应用,持久层使用的是MyBatis
。
2 架构
一个最简单的Spring Boot Web
应用分为三层:
Controller
层:负责具体业务流程的控制,调用Service
层来控制业务逻辑Service
层:业务逻辑层,真正执行业务的操作,比如获取用户信息等Dao
层:负责数据持久化,在这一层中与各种数据库,比如MySQL
、Oracle
等打交道
先来简单说一下三层所使用到的注解。
2.1 Controller
层
Controller
层也是入口层,一般涉及如下注解:
@Controller
:@Controller
是经典的Controller
层注解,@Controller
标识的类代表该类是控制器类@RequestMapping
:使用@RequestMapping
可以对请求进行映射,可以注解在类上或者方法上,在类上的话表示该类所有的方法都是以该地址作为父地址,在方法上就表示可以映射对应的请求到该方法上@GetMapping/@PostMapping
:这两者实际上是@RequestMapping
对应不同方法的简化版,因为@RequestMapping
有一个method
属性,如果该method
指定为GET
那么就相当于@GetMapping
,如果指定为POST
就相当于@PostMapping
@ResponseBody
:作用在方法上,将返回的数据进行可能的转换(取决于请求头,转换为JSON
或XML
等等,默认的情况下比如单纯字符串就直接返回),比如返回语句为return "success";
,如果加上了@ResponseBody
就直接返回success
,如果不加上就会跳转到success.jsp
页面@RequestParm
:处理Contrent-Type
为application/x-www-form-urlencoded
的内容,可以接受简单属性类型或者对象,支持GET
+POST
@RequestBody
:处理Content-Type
不为application/x-www-form-urlencoded
的内容(也就是需要指定Content-Type
),不支持GET
,只支持POST
@PathVariable
:可以将占位符的参数传入方法参数,比如/path/1
,可以将1
传入方法参数中@PathParm
:与@RequestParm
一样,一般使用@RequestParm
@RestController
:相当于@Controller
+@ResponseBody
2.2 Service
层
Service
层用于执行主要的业务逻辑,主要就是下面这个注解:
@Serice
:是一个增强型的@Component
,@Component
表示一个最普通的组件,可以被注入到Spring
容器进行管理,而@Service
是专门用于处理业务逻辑的注解,@Controller
类似,也是一个增强型的@Component
,专门用于Controller
层的处理
2.3 Dao
层
Dao
是数据持久层,这里进行数据持久化的操作,一般加上@Repository
即可:
@Repository
:也是一个增强型的@Component
,注解在持久层中,具有将具体数据库抛出的异常转为Spring
持久层异常的功能
讲完注解了下面就开始实践一下。
3 实践
3.1 新建项目
选择如下依赖:
Lombok
能简化代码,推荐使用,并且需要IDEA
安装插件。ORM
框架这里选择MyBatis
。
3.2 新建包
新建如下四个包:
controller
dao
entity
service
config
3.3 Controller
层
3.3.1 简单Controller
在controller
包下新建Controller.java
:
@RestController
@RequestMapping("/")
public class Controller {
@GetMapping("test")
public String testMethod()
{
return "test controller";
}
}
运行之后,如果出现如下错误:
这是因为没有配置数据源,可以先把MySQL
和MyBatis
的依赖删去:
运行之后在浏览器输入localhost:8080/test
会返回test controller
:
这样一个最简单的Controller
就完成了。
3.3.2 @RequestParm
然后下一步是添加参数,可以考虑使用@RequestParm
添加:
@GetMapping("withParm")
public String withParm(@RequestParam String id)
{
return "id:"+id;
}
这样直接访问localhost:8080/withParm
是不行的,因为没有携带id
参数:
加入参数即可,也就是localhost:8080/withParm?id=1
:
3.3.3 @PathVariable
另一种添加参数的方式是使用@PathVariable
:
@GetMapping("path1/{id}")
public String path1(@PathVariable("id") String id)
{
return "id:"+id;
}
这样不是加入?id=xx
,而是直接加入占位符,比如localhost:8080/path1/1
:
3.3.4 完整CURD
这里是一个完整的CRUD
示例:
@RestController
@RequestMapping("/")
@CrossOrigin("http://localhost:3000")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class CRUDController {
private final Service service;
@PostMapping("save")
public boolean save(@RequestBody User user)
{
return service.save(user);
}
@GetMapping("delete")
public boolean delete(@RequestParam String id)
{
return service.delete(id);
}
@GetMapping("select")
public User select(@RequestParam String id)
{
return service.select(id);
}
@GetMapping("selectAll")
public List<User> selectAll()
{
return service.selectAll();
}
}
注解基本上都在上面说过了,除了下面两个:
@RequiredArgsConstrutcor
:这个是Lombok
的注解,用来消除直接使用@Autowired
出现的警告@CrossOrgin
:跨域注解,由于笔者使用Postwoman
测试,默认运行端口为3000
,因此需要加上该注解,使用Postman
测试则不需要
3.4 Service
层
@org.springframework.stereotype.Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class Service {
private final UserMapper mapper;
public boolean save(User user)
{
String id = user.getId();
User currentUser = select(id);
if(currentUser != null)
return mapper.update(user) == 1;
return mapper.insert(user) == 1;
}
public boolean delete(String id)
{
return mapper.deleteById(id) == 1;
}
public User select(String id)
{
return mapper.selectById(id);
}
public List<User> selectAll()
{
return mapper.selectAll();
}
}
简单的CRUD
,调用持久层的方法。
3.5 Dao
层
由于使用MyBatis
,这里的Dao
层只有一个Mapper
:
@Mapper
@Component
public interface UserMapper{
@Select("select * from user where id=#{id}")
User selectById(@Param("id") String id);
@Select("select * from user")
List<User> selectAll();
int insert(@Param("user") User user);
int deleteById(@Param("id") String id);
int update(@Param("user") User user);
}
select
的sql
直接写在了上面,剩下的sql
语句写在了xml
配置文件,另外@Mapper
注解表示在编译后生成对应的接口实现类。
3.6 实体类
@Data
@AllArgsConstructor
public class User {
private String id;
private String username;
private String password;
@Override
public String toString()
{
return "id:"+id+"\n"+"username"+username+"\npassword"+password+"\n";
}
}
3.7 配置类
@Configuration
@MapperScan("com.example.demo.dao")
public class MyBatisConfig {
}
@Configuration
:定义为配置类@MapperScan
:@Mapper
的扫描路径
3.8 配置文件
配置文件常用的有properties
以及yaml
,yaml
格式更加简单,这里使用yaml
格式:
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/test
username: test
password: test
mybatis:
configuration:
map-underscore-to-camel-case: true
mapper-locations: classpath:mappers/*.xml
分别指定数据库链接,数据库用户名以及密码,还有下划线转驼峰命名以及mapper
文件的位置。
另外还需要创建UserMapper.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.example.demo.dao.UserMapper">
<insert id="insert">
INSERT INTO `user` (`id`,`username`,`password`)
VALUES (#{user.id},#{user.username},#{user.password})
</insert>
<update id="update">
UPDATE `user` set `username`=#{user.username} , `password`=#{user.password} where id=#{user.id}
</update>
<delete id="deleteById">
DELETE FROM `user` WHERE `id` = #{id}
</delete>
</mapper>
就单纯的sql
语句。
另外需要准备建表以及建用户的sql
:
CREATE DATABASE IF NOT EXISTS test;
CREATE USER IF NOT EXISTS 'test'@'localhost' IDENTIFIED BY 'test';
GRANT ALL ON test.* to 'test'@'localhost';
USE test;
CREATE TABLE user
(
id char(10) primary key ,
username varchar (30) not null,
password varchar (30) not null
);
测试数据:
USE test;
INSERT INTO user(id,username,password) values ('1','username1','password1'),('2','username2','password2');
最终配置文件如下:
4 其他准备
4.1 建库建表建用户
直接执行上面的脚本即可。
4.2 开启服务
使用相应命令开启数据库服务。
5 测试
5.1 单元测试
修改一下自带的测试类即可:
@SpringBootTest
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
class DemoApplicationTests {
private final Service service;
@Test
void contextLoads() {
}
@Test
void select()
{
System.out.println(service.select("1"));
}
@Test
void selectAll()
{
service.selectAll().forEach(System.out::println);
}
// @Test
// void delete()
// {
// service.delete("3");
// }
@Test
void save()
{
service.save(new User("3","username3","password3"));
}
}
直接点击左边的按钮即可运行,测试通过图如下:
5.2 浏览器测试
由于没有做前端,这里就使用Postwoman
模拟前端测试:
6 源码
Java
版:
Kotlin
版:
7 参考
Spring Boot demo系列(二):简单三层架构Web应用的更多相关文章
- Spring Boot进阶系列二
上一篇文章,主要分析了怎么建立一个Restful web service,系列二主要创建一个H5静态页面使用ajax请求数据,功能主要有添加一本书,请求所有书并且按照Id降序排列,以及查看,删除一本书 ...
- Spring Boot demo系列(五):Docker部署
2021.2.24 更新 1 概述 本文讲述了如何使用Docker部署Spring Boot应用,首先介绍了Docker的安装过程,接着介绍了Docker的一些基础知识,最后讲述了Dockerfile ...
- Spring Boot demo系列(四):Spring Web+Validation
2021.2.24 更新 1 概述 本文主要讲述了如何使用Hibernate Validator以及@Valid/@Validate注解. 2 校验 对于一个普通的Spring Boot应用,经常可以 ...
- Spring Boot demo系列(十):Redis缓存
1 概述 本文演示了如何在Spring Boot中将Redis作为缓存使用,具体的内容包括: 环境搭建 项目搭建 测试 2 环境 Redis MySQL MyBatis Plus 3 Redis安装 ...
- Spring Boot demo系列(九):Jasypt
2021.2.24 更新 1 概述 Jasypt是一个加密库,Github上有一个集成了Jasypt的Spring Boot库,叫jasypt-spring-boot,本文演示了如何使用该库对配置文件 ...
- Spring Boot demo系列(六):HTTPS
2021.2.24 更新 1 概述 本文演示了如何给Spring Boot应用加上HTTPS的过程. 2 证书 虽然证书能自己生成,使用JDK自带的keytool即可,但是生产环境是不可能使用自己生成 ...
- Spring Boot demo系列(一):Hello World
2021.2.24 更新 1 新建工程 打开IDEA选择新建工程并选择Spring Initializer: 可以在Project JDK处选择JDK版本,下一步是选择包名,语言,构建工具以及打包工具 ...
- Spring Boot教程(二十一)开发Web应用(2)
在完成配置之后,举一个简单的例子,在快速入门工程的基础上,举一个简单的示例来通过Thymeleaf渲染一个页面. @Controller public class HelloController { ...
- Spring Boot教程(二十四)Web应用的统一异常处理
我们在做Web应用的时候,请求处理过程中发生错误是非常常见的情况.Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来 ...
随机推荐
- Java中Singleton的三种实现方式解析
一.什么是Singleton? <设计模式>的作者.Eclipse和 Junit 的开发者 Erich Gamma 在它的理论体系中将 Singleton 定义为仅仅被实例化一次的类.在当 ...
- AtCoder Beginner Contest 192 F - Potion
题目链接 点我跳转 题目大意 给定 \(N\) 个物品和一个 \(X\) ,第 \(i\) 个物品的重量为 \(ai\),你可以从中选择任意个物品(不能不选) 假定选择了 \(S\) 个物品,物品的总 ...
- linux下安装mysql8.0.x步骤
1.下载mysql mysql官网:https://dev.mysql.com/downloads/mysql/ 将下载的mysql上传打linux 2.解压并重命名 [root@rsyncClien ...
- 【转载】Win10彻底格式化磁盘防止数据恢复的技巧
转载地址 注意 要尽量删除数据,请在运行cipher /w时关闭其他所有应用程序. 1.如果你在格式化磁盘后想要防止数据被恢复, Format 命令,而现在只需在其后添加 /P 参数,即可用随机数据覆 ...
- 模拟web服务器 (小项目) 搭建+部署
模拟web服务器:可以从浏览器中访问到自己编写的服务器中的资源,将其资源显示在浏览器中. 技术选型: corejava 线程池 同任务并发执行 IO流 传递数据 客户端也会像服务端发送数据, 服务器像 ...
- c#winform主题实现的一个方法
winform的主题实现没有bs里面那么舒服,下面做了一个简单实现,记录一下. 1.一个接口,需要做主题的控件.窗体都要实现这个接口 /// <summary> /// 使用主题的控件.窗 ...
- 死磕Spring之IoC篇 - BeanDefinition 的解析过程(面向注解)
该系列文章是本人在学习 Spring 的过程中总结下来的,里面涉及到相关源码,可能对读者不太友好,请结合我的源码注释 Spring 源码分析 GitHub 地址 进行阅读 Spring 版本:5.1. ...
- .Net -- NLog日志框架配置与使用
NLog是适用于各种.NET平台(包括.NET标准)的灵活,免费的日志记录平台,NLog可将日志写入多个目标,比如Database.File.Console.Mail.下面介绍下NLog的基本使用方法 ...
- PUToast - 使用PopupWindow在Presentation上模拟Toast
PUToast Android10 (API 29) 之前 Toast 组件默认只能展示在主 Display 上,PUToast 通过构造一个 PopupWindoww 在 Presentation ...
- 【Azure 云服务】Azure Cloud Service在发布新部署后遇见不能RDP(远程连接)到实例时如何处理?
Azure 云服务是PaaS 的一个示例. 与 Azure 应用服务一样,此技术设计用于支持可缩放.可靠且运营成本低廉的应用程序. 同样,应用服务托管在虚拟机 (VM) 上,Azure 云服务也是如此 ...