java三层架构是哪三层_Spring Boot demo系列(二):简单三层架构Web应用

1 概述

这是Spring Boot的第二个Demo,一个只有三层架构的极简Web应用,持久层使用的是MyBatis

2 架构

一个最简单的Spring Boot Web应用分为三层:

  • Controller层:负责具体业务流程的控制,调用Service层来控制业务逻辑
  • Service层:业务逻辑层,真正执行业务的操作,比如获取用户信息等
  • Dao层:负责数据持久化,在这一层中与各种数据库,比如MySQLOracle等打交道

先来简单说一下三层所使用到的注解。

2.1 Controller

Controller层也是入口层,一般涉及如下注解:

  • @Controller@Controller是经典的Controller层注解,@Controller标识的类代表该类是控制器类
  • @RequestMapping:使用@RequestMapping可以对请求进行映射,可以注解在类上或者方法上,在类上的话表示该类所有的方法都是以该地址作为父地址,在方法上就表示可以映射对应的请求到该方法上
  • @GetMapping/@PostMapping:这两者实际上是@RequestMapping对应不同方法的简化版,因为@RequestMapping有一个method属性,如果该method指定为GET那么就相当于@GetMapping,如果指定为POST就相当于@PostMapping
  • @ResponseBody:作用在方法上,将返回的数据进行可能的转换(取决于请求头,转换为JSONXML等等,默认的情况下比如单纯字符串就直接返回),比如返回语句为return "success";,如果加上了@ResponseBody就直接返回success,如果不加上就会跳转到success.jsp页面
  • @RequestParm:处理Contrent-Typeapplication/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 新建项目

选择如下依赖:

ede8a001d37a79bf516484887ef1102f.png

Lombok能简化代码,推荐使用,并且需要IDEA安装插件。ORM框架这里选择MyBatis

3.2 新建包

新建如下四个包:

  • controller
  • dao
  • entity
  • service
  • config

189d4a3bae812919189fd9c681c3a72b.png

3.3 Controller

3.3.1 简单Controller

controller包下新建Controller.java

@RestController
@RequestMapping("/")
public class Controller {
    @GetMapping("test")
    public String testMethod()
    {
        return "test controller";
    }
}

运行之后,如果出现如下错误:

9c810cf3c91a5ffd8e72b4839a095def.png

这是因为没有配置数据源,可以先把MySQLMyBatis的依赖删去:

b20679288b50f527602fcf57512f50a2.png

运行之后在浏览器输入localhost:8080/test会返回test controller

46f3f3c955f835b79a39ec6411f116e1.png

这样一个最简单的Controller就完成了。

3.3.2 @RequestParm

然后下一步是添加参数,可以考虑使用@RequestParm添加:

@GetMapping("withParm")
public String withParm(@RequestParam String id)
{
    return "id:"+id;
}

这样直接访问localhost:8080/withParm是不行的,因为没有携带id参数:

addf3623be37f73e3976fad173ddd4de.png

加入参数即可,也就是localhost:8080/withParm?id=1

ba3026d08ea3b7546f81ff77f4584725.png

3.3.3 @PathVariable

另一种添加参数的方式是使用@PathVariable

@GetMapping("path1/{id}")
public String path1(@PathVariable("id") String id)
{
    return "id:"+id;
}

这样不是加入?id=xx,而是直接加入占位符,比如localhost:8080/path1/1

8dd36d7fc30a9ee7b1f2e2454e0334e6.png

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);
}

selectsql直接写在了上面,剩下的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 配置文件

c20d75bbff3d4d6c14288c3fa105c0d9.png

配置文件常用的有properties以及yamlyaml格式更加简单,这里使用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');

最终配置文件如下:

9e010ba2fef4367b343edbed8e37665c.png

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"));
    }
}

fedc5e9f87d61f0b4a0683f5a0f51e76.png

直接点击左边的按钮即可运行,测试通过图如下:

8312eaa52fe326f8ad452db712577373.png

5.2 浏览器测试

由于没有做前端,这里就使用Postwoman模拟前端测试:

6cc4980133c106a9f424d9b91a3b6ee2.png

ca6f0018e25c2ad00061afeed47da72f.png

d0b1c56893b932d8c49b48ffd8375e25.png

257c0c13580c6787e46698be7da1f4dd.png

6 源码

Java版:

  • Github
  • 码云

Kotlin版:

  • Github
  • 码云

7 参考

  • Spring Boot Demo MyBatis
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值