Spring Boot专栏四:使用Spring Boot的框架,进行数据库的操作


今天我们来结合专栏二和专栏三的内容,使用Spring Boot的框架,进行数据库的操作。在专栏三中,我们是自顶向下地介绍了框架;本节则是自底向上,通过代码向大家展示如何读取数据库中的数据。

数据库中的内容

本节我们仍然使用到第二节中创建好的user_类,内容也不变,具体内容不再赘述,请大家自行查阅,链接为:数据库操作

创建一个Model

最底层的东西当然是我们的模型啦,其实也就是一个类,或者是一个实体(如果大家会画ER图,一定会对这个实体有印象吧)。所有类应当放到同一个文件夹中,我个人习惯把这个文件夹叫做entity,有些人可能会叫model或者bean,这个没有关系,只是习惯问题。
于是,我们在main/java/com/example/demo下创建entity文件夹,在entity文件夹中建一个类,因为我们现在仍然对用户进行操作,所以创建一个叫做User的类吧。

POJO

我们之前介绍了POJO,因此我们需要

  1. 对mysql表中的每一种字段、属性,都设为User类中的一个私有属性
  2. 对上述每个属性设置公有的set和get方法
  3. 添加全参构造器和无参构造器

User类的代码

Spring Boot可以便捷地完成上述这些内容,代码如下:

package com.example.demo.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.log4j.Log4j;

@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
@Log4j
public class User {
    @Setter
    @Getter
    private int user_id;
    @Setter
    private String user_name;
    public String get_user_name() {
        return user_name;
    }
    @Setter
    private String user_phone;
    public String get_user_phone() {
        return user_phone;
    }
    @Setter
    private String user_password;
    public String get_user_password() {
        return user_password;
    }
    @Setter double user_wallet;
    public double get_user_wallet() {
        return user_wallet;
    }
    @Setter
    private String register_time;
    public String get_register_time() {
        return register_time;
    }
    @Setter
    private String login_time;
    public String get_login_time() {
        return login_time;
    }

    public User(String user_name, String user_password) {
        this.user_name = user_name;
        this.user_password = user_password;
    }

    public User(String user_name, String user_password, String register_time, String login_time) {
        this.user_name = user_name;
        this.user_password = user_password;
        this.register_time = register_time;
        this.login_time = login_time;
    }
}

注解的简单解释

可以看到,每个属性都是私有的,同时我们可以用对属性的@Setter和@Getter注解来实现共有的set和get方法,另外用对类的@AllArgsConstructor和@NoArgsConstructor注解来实现全参构造和无参构造。
除此之外,对类还有三个注解,我分别解释一下:@Data注解,表示建了一个POJO类(实际上它包含了此处的其他几个注解);@EqualsAndHashCode,自动生成equals(Object other)和hashCode()方法;@Log4j用来获取日志。

要注意的事情!!!

但大家也发现到一些问题,我自己也觉得我写得不好,我先说一下我哪里写得不好,大家可以一起讨论,也可以指出我的其他缺点:

  1. 没有使用驼峰规则。确实我没有规范地命名,从数据库的属性命名中就可以看到,我是比较懒散的。希望大家可以规范命名,以后当了项目经理也得带着团队一起规范命名;
  2. 我这里只有user_id处用了@Getter注解。实际上,在我的实践中,我发现Getter注解实在是不好用,很多时候甚至导致程序出错!大家一定要对于每个属性都自己实现一个get方法。
  3. 构造函数仍然要自己来写,不管是全参的,还是部分参数的,都根据需求重新写一遍,不要相信@AllArgsConstructor注解!我这里没有写全参的构造函数,是因为可能创建一个User类时,你还不知道user_id是多少,但是如果某个场景下已知user_id,那么我们一定要写上带有user_id的构造函数。

有关于上述的2、3两个问题,有机会我专门开一节来举例子说明(继续挖坑)

Dao层

Dao层是与数据库相关的操作层,在Spring Boot项目中它需要分为两部分来写。

Dao接口

第一个部分,是一些接口。我们在main/java/com/example/demo下创建dao文件夹(也有人叫mapper,这个只是命名习惯,关系不大)。在dao文件夹中,针对于我们的项目,创建一个UserDao.java文件,记得要选择将其定义为一个接口interface,而不是类。
然后,对于这个接口要添加一些注解。在"public interface UserDao {"的上一行,我们添加两个注解:
@Mapper
@Repository(“UserDao”)
这两个注解的意义,可以参考博客Spring 与 Mybatis 中的 @Repository 与 @Mapper
简单来说,@Mapper 是 Mybatis 的注解,和 Spring 没有关系;@Repository 是 Spring 的注解,用于声明一个 Bean。
在 Spring 程序中,Mybatis 需要找到对应的 mapper,在编译的时候动态生成代理类,实现数据库查询功能,所以我们需要在接口上添加 @Mapper 注解。
而 @Repository注解则是用于基于代码的开发,简单来说就是手写 JDBC。这也和我们的下一部分有关。
现在假设我们需要实现最简单的全部查询功能,和根据用户名查询的功能,那么我们就在UserDao.java文件中写这些代码:

package com.example.demo.dao;

import com.example.demo.entity.User;

import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

import java.util.List;

@Mapper
@Repository("UserDao")
public interface UserDao {

    List<User> show_user_all();

    List<User> show_user_by_user_name(@Param("user_name") String user_name);
}

这样就完成了UserDao接口的内容。其中,在第二个方法中有个@Param(“user_name”)注解,实际上它是和JDBC语言有关,我们暂且不提。

写相关的数据库sql语句

下面就要我们手写JDBC的XML代码了。那么,我们在哪里创建文件呢?我在个人实践中也碰到过这个问题,百度了非常久,我记得大概有两天的时间都被这个问题耽搁了。
按照网上的说法,放在任何一个位置都可以,只要文件中的一个地方配置好即可。
但我个人习惯(也是多次尝试后的无奈之举),在main/resources下创建文件夹com,在其中创建文件夹example,在其中创建文件夹demo,在其中创建文件夹dao,在其中创建文件UserDao.xml——那么,这个文件的路径就变为:main/resources/com/example/demo/dao/UserDao.xml,与刚才创建的UserDao接口的路径main/java/com/example/demo/dao/UserDao.java相比,有很高的相似性。
然后,在UserDao.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.UserDao">

    <select id="show_user_all" resultType="com.example.demo.entity.User">
        select user_name, user_password, register_time, login_time
        from user_
    </select>

    <select id="show_user_by_user_name" parameterType="String" resultType="com.example.demo.entity.User">
        select user_name, user_password, register_time, login_time
        from user_
        where user_name=#{user_name}
    </select>

</mapper>

最需要注意的是第5行:

<mapper namespace="com.example.demo.dao.UserDao">

这句话,就是我上面说的“只要文件中的一个地方配置好即可”的地方。大家如果感兴趣,也可以看看将UserDao.xml放到其他路径下试一试,按理说都是好使的,不过我是不想再折腾了,当时白费两天时间调来调去的……
其他需要注意的部分就是JDBC语句的写法。我相信大家都有sql语句的基础,只是不知道<select …>这些地方怎么写,还有下面的#{user_name}的问题(其实是和Dao接口中的@Param注解有关)。这个部分,就待我另开一节来讲讲吧,今天暂且不提。

Service层

Service层也分为两部分,不过它们处在同一个文件夹下,而且都是用java代码来写的。

Service接口

首先在main/java/com/example/demo下创建service文件夹,根据我们的项目,在其中创建UserService.java,注意,UserService也是个接口。有一个好消息,就是在这里我们不需要添加任何注解!!!
针对于全部查询功能,和根据用户名查询的功能,我们在UserService.java文件中这样写代码:

package com.example.demo.service;

import com.example.demo.entity.User;

import java.util.List;

public interface UserService {

    List<User> show_user_all();

    List<User> show_user_by_user_name(String user_name);
}

ServiceImpl类

Service接口必须有个实现类。我们在serivce文件夹下新建一个Impl文件夹,在Imple文件夹下创建UserServiceImpl.java,作为UserService接口的实现类,因此在UserServiceImpl类后需要加上 implements UserService.
然后,对于这个类要添加一些注解。在"public class UserServiceImpl implements UserService {"的上一行,我们添加一个注解:
@Service(“UserService”)
用来定义业务层Bean
因为实现类要实现接口的方法,所以我们可以直接重载UserService接口中的方法,具体代码如下:

package com.example.demo.service.impl;

import com.example.demo.dao.UserDao;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


@Service("UserService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;

    @Override
    public List<User> show_user_all() {
        return userDao.show_user_all();
    }

    @Override
    public List<User> show_user_by_user_name(String user_name) {
        return userDao.show_user_by_user_name(user_name);
    }

}

我们看到,其中还要通过@Autowired注解创建一个Bean类(接口),是与UserDao有关的,因为业务层实际上是调用UserDao的数据库操作来实现的。

Controller层

controller层是我们能够自主发挥最多的部分了,可以在这里做一些输出、比较等等,反正写起来是比较舒服了。我们之前已经在controller文件夹下创建过TestController.java文件了,因此可以在这个文件夹下继续创建其他相似文件,比如UserController文件。
由于我们要实现全部查询,和根据用户名查询这两个功能,因此我们写两个方法。代码的简单实现如下所示:

package com.example.demo.controller;

import java.util.List;

import com.example.demo.entity.User;
import com.example.demo.service.UserService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {
    
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/show_user_all", method = {RequestMethod.GET})
    public List<User> show_user_all() {
        List<User> result = userService.show_user_all();
        int len = result.size();
        System.out.println("共查询到"+len+"条记录");
        for (int i = 0;i < len;i++) {
            User user = result.get(i);
            String user_name = user.get_user_name();
            String user_password = user.get_user_password();
            String register_time = user.get_register_time();
            String login_time = user.get_login_time();
            System.out.println("第"+(i+1)+"条记录的用户名为"+user_name+",密码为"+user_password+",注册时间为"+register_time+",最后一次的登录时间为"+login_time);
        }
        return result;
    }

    @RequestMapping(value = "/show_user_by_user_name", method = {RequestMethod.GET})
    public List<User> show_user_by_user_name(@RequestParam("user_name") String user_name) {
        List<User> result = userService.show_user_by_user_name(user_name);
        int len = result.size();
        System.out.println("共查询到"+len+"条记录");
        for (int i = 0;i < len;i++) {
            User user = result.get(i);
            String user_password = user.get_user_password();
            String register_time = user.get_register_time();
            String login_time = user.get_login_time();
            System.out.println("第"+(i+1)+"条记录的用户名为"+user_name+",密码为"+user_password+",注册时间为"+register_time+",最后一次的登录时间为"+login_time);
        }
        return result;
    }

}

该部分代码的注解比较多,我们全部放到下次讲注解的时候去讲。大家主要学习的就是怎么样得到输入,获取查询结果,并输出查询结果。

结果演示

全部查询功能

启动项目后,在浏览器中输入http://localhost:8080/user/show_user_all,得到如下界面,则为成功。
全部查询功能浏览器显示图片
同时,VSCode终端也应该输出:
全部查询功能VSCode终端显示图片

根据用户名查询功能

启动项目后,在浏览器中输入http://localhost:8080/user/show_user_by_user_name?user_name=dante,得到如下界面,则为成功。
根据用户名查询功能浏览器显示图片
同时,VSCode终端也应该输出:
根据用户名查询功能VSCode终端显示图片

通过本节的讲解,我希望大家能够理解Spring Boot是怎么样实现MVC设计模式的,其中数据的流动又是怎么样的。这是一个非常简单的例子。如果想要实现更复杂的功能,我们还需学习一些高级的内容,那就放到下一节讲吧。

另外,为了方便大家拷贝代码,我已经将我的项目放到了github上,项目地址为https://github.com/DTSSDUTDeepLearning/Spring-Boot-Dante,有需求的朋友们自行前往下载。

谢谢大家的阅读。

专栏第五节已经更新啦,传送门:Spring Boot专栏五:Spring Boot中的注解的解释(一)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值