SpringBoot入门(四)Service、Dao

1,135 阅读5分钟

为什么Service和Dao层放在一起写,是因为Service业务与Dao层紧密关联,当然在测试阶段,如果在没有Dao层的情况下,我们可以在Service里放一些伪数据来方便测试!

首先,肯定是需要安装数据库了,本教程中使用的是Mysql数据库,安装步骤就不再说了,默认大家都已安装好了Mysql并可以连接使用!

注意:本教程中连接的是远程服务器,mysql,redis等都是放在远程服务器中的,服务器系统为Linux,因此建议看此系列教程的同学最好能有一样的服务器环境,会减少出错几率,后面可能会讲解docker在linux上的使用方法,如果环境不一样,会浪费不少时间!

此篇文章,我们先来使用JPA,来作为数据持久化层,需要引入的资源有jdbc、jpa、mysql-connector、druiddruid是什么?

阿里官方定义:

Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能

我们使用来Druid代替原生的数据源,正如它所说,它提供了强大的监控能力,所有有关数据库的查询信息,都可以在Druid后台查看!

pom.xml引入相关资源:

  <!--jdbc-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jdbc</artifactId>
  </dependency>
  <!--持久化框架jpa-->
  <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <!--mysql数据库-->
  <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <scope>runtime</scope>
  </dependency>
  <!--druid数据源 -->
  <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.2.1</version>
  </dependency>

application.yml中配置:

spring:
  resources:
    static-locations: classpath:/static/, classpath:/templates/
  datasource:
    username: root
    password: root
    url: jdbc:mysql://39.xxx.x.xx:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Hongkong
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource
    #druid
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    filters: stat,wall,slf4j,config
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
  jpa:                 #JPA配置
    hibernate:
      ddl-auto: none   #数据库有表就更新,无表就创建
    show-sql: true     #显示sql语句

数据库datasource的用户名,密码,数据库名,地址,这些安装时都应该知道,替换上即可!其它的可以原封不动的复制下来,因为这些配置几乎都是固定的!

创建DruidConfig类,来配置druid相关的一些东西:

在这里插入图片描述

DruidConfig:

@Configuration
public class DruidConfig {

    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid() {
        return new DruidDataSource();
    }

    /**
     * 配置druid监控路径、登录账号密码,以及其它一些参数
     * (访问链接:http://localhost:8080/byl/druid)
     *
     * @return
     */
    @Bean
    public ServletRegistrationBean<StatViewServlet> statViewServlet() {
        ServletRegistrationBean<StatViewServlet> bean = new ServletRegistrationBean<>(new StatViewServlet(), "/druid/*");
        Map<String, String> initParas = new HashMap<>();
        initParas.put("loginUsername", "admin");//druid登录用户名
        initParas.put("loginPassword", "admin");//druid登录密码
        initParas.put("allow", "localhost");//只允许本机访问,多个ip用逗号隔开
        //initParas.put("deny","");//拒绝访问
        initParas.put("resetEnable", "false");//禁用HTML页面的Reset按钮
        bean.setInitParameters(initParas);
        return bean;
    }

    /**
     * 设置过滤器
     *
     * @return
     */
    @Bean
    public FilterRegistrationBean<WebStatFilter> webStatFilter() {
        FilterRegistrationBean<WebStatFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new WebStatFilter());
        bean.addUrlPatterns("/*");
        Map<String, String> initParams = new HashMap<>();
        initParams.put("exclusions", "*.js,*.css,/druid/*");//排除不需要监控的资源
        bean.setInitParameters(initParams);
        return bean;
    }

}

注意 @Configuration注解,SpringBoot中所有配置相关的类都会通过它注解生效!而 @Bean则是向SpringBoot容器中添加组件,并交由SpringBoot管理!

在数据库中创建表(测试过程中可以随意创建,仅测试dao与数据库的连通性即可):

在这里插入图片描述

创建对应数据库表的Bean:

在这里插入图片描述

User:

package com.byl.springboottest.bean;

import javax.persistence.*;

@Entity(name = "user")
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
    private Integer id;
    @Column
    private Integer dept_id;
    @Column
    private String user_name;
    @Column
    private String nick_name;
    @Column
    private String password;

    public Integer getDept_id() {
        return dept_id;
    }

    public void setDept_id(Integer dept_id) {
        this.dept_id = dept_id;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public String getNick_name() {
        return nick_name;
    }

    public void setNick_name(String nick_name) {
        this.nick_name = nick_name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

@Entity(name = "user")声明对应的表名,@Column声明对应的字段名,需要注意的是,如果数据库中定义的字段带下划线“_”,那么我们的Bean的映射字段要采用驼峰命名规则,因此需要修改为:

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
    private Integer id;
    @Column(name="dept_id")
    private Integer deptId;
    @Column(name="user_name")
    private String userName;
    @Column(name="nick_name")
    private String nickName;
    @Column
    private String password;

书写Dao(JPA创建Dao方式,继承JpaRepository):

在这里插入图片描述

UserRepository:

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {


}

不要忘了@Repository注解!其中JpaRepository<User, Integer>的第一个参数就是对应的Bean,第二个参数则是该Bean中(数据库中)对应的Id的类型!

此时打开test文件夹下的SpringboottestApplicationTests类,引入资源UserRepository ,并添加测试方法:

@SpringBootTest
class SpringboottestApplicationTests {

    @Resource
    UserRepository userRepository;

    @Test
    void contextLoads() {

    }

    @Test
    void testDao() {
        Optional<User> optional = userRepository.findById(2);
        System.out.println("获取用户成功>>" + optional.get().getNickName());
    }
}

执行testDao方法: 在这里插入图片描述 运行结果: 在这里插入图片描述 此时表明,数据库连接,映射,操作都已经没有问题了!

浏览器打开:http://localhost:8080/byl/druid 在这里插入图片描述 输入DruidConfig中配置的用户名(admin)和密码(admin)进入:

在这里插入图片描述 刚才我们的查询操作记录,已经静静的躺在那里了!

继续往下说,关于JPA的用法,JPA本身提供了一些基础的增删改查方法: 在这里插入图片描述 不用写sql而直接调用方法使用,我们也可以在UserRepository定义复杂的查询方法,比如JPA原生只提供了findById的方法,我想通过用户名查怎么办?

那就可以自己写一个findByUserName的方法: 在这里插入图片描述 你会发现,它提供了一些列关于字段的操作方法,完全不在需要你去手写sql了,当然如果遇到比较复杂需要手写sql的时候,jpa也是支持的:

    @Query(value = "select * from user where id = ?", nativeQuery=true)
    User getUser(Integer id);

更详细的用法,可以看文档喽!

测试通过后,我们终于来到了业务层Service,在写Service之前,我们要了解Service层的结构,就是接口+实现的方式:

首先定义interface:

public interface UserService {

    User getUserById(Integer id);

    User getUserByName(String username);
}

然后写实现类Impl:

public class UserServiceImpl implements UserService{

    @Override
    public User getUserById(Integer id) {
        return null;
    }

    @Override
    public User getUserByName(String username) {
        return null;
    }
}

为什么一定要先写个接口,再写个实现类呢,为什么要这么麻烦,我直接写一个Service,咔咔的就开始写业务岂不是更简单吗?

如果有这个疑问,建议可以先了解一下interface 这个东西,Java为啥要出这么个东西?!

这里我只简单的说下它的两个优点:

1.制定规范:我定义一个了interface,却可以有n个实现,我的控制层并不关心你的实现方法,我只调用我定义的interface,你的实现只用给我返回我需要的数据就可以了!这样的好处就是,一旦业务有所变动,我只需要修改实现方法即可,甚至可以有多套实现来回切换!SpringBoot中也大量运用这种思想,定义接口,第三方实现,那么我在项目中就可以随意去切换第三方的实现库了!

2.适合团队开发:当在开发一个新项目时,可能要分工了,A写Controller层,B写Service层,A在写Controller层时肯定需要调用Service的东西,但是此时Service层并没有东西呢怎么调?难道我要等待B把Service都写好了我再开始干活?或者我先定义一堆假数据自己先玩着,等B把Service写好后在去修改?这样都极大了拖慢了工作效率,那么此时A或B就可以去定义Service接口了,这将很快,之后A就可以直接去调用接口了,而不用在等待B的具体业务实现!

我们继续完成UserServiceImpl 的实现:

@Service
public class UserServiceImpl implements UserService {

    @Resource
    UserRepository userRepository;

    @Override
    public User getUserById(Integer id) {
        return userRepository.findById(id).get();
    }

    @Override
    public User getUserByName(String username) {
        return userRepository.findByUserName(username);
    }
}

注意不要忘了添加 @Service注解,代表它是一个Service!

UserController:

@RestController
@RequestMapping("/user")
public class UserController {

    @Resource
    UserService userService;

    @GetMapping("/{id}")
    public User getUserById(@PathVariable Integer id) {
        return userService.getUserById(id);
    }


    @GetMapping("/getUserByName")
    public User getUserByName(String username) {
        return userService.getUserByName(username);
    }

}

浏览器输入:http://localhost:8080/byl/user/2 在这里插入图片描述 输入:http://localhost:8080/byl/user/getUserByName?username=baiyuliang 在这里插入图片描述 这样我们就完成了一个简单的从Controller到Service再到Dao层的接口请求!