springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序

一、项目目标

    开发一个IP地址查询功能的REST-API程序,实现对指定IP地址的国家、省、市及运营商信息查询,如果没有参数指定具体Ip地址则自动将来访IP作为查询IP地址进行返回信息。

    设计实现效果如下:

1、有查询ip参数指定情况

    http://localhost:8080/getipinfo?ip=202.103.44.150

    [{"id":1,"ipadd":"202.103.44.150","country":"中国","privince":"湖北省","city":"武汉市","isp":"电信"}]

2、无指定查询ip参数情况

   http://localhost:8080/getipinfo

     [{"id":1,"ipadd":"58.51.94.1","country":"中国","privince":"湖北省","city":"武汉市","isp":"电信"}]

二、涉及技术分析

1、数据库部分

  数据库直接使用上一篇博文的成果,使用docker起一个mysql数据库,数据库名为ipdb,账号root,密码123456

2、springboot涉及数据库操作部分-spring data JPA

Spring Data JPA是更大的Spring Data系列的一部分,可以轻松实现基于JPA的存储库。此模块处理对基于JPA的数据访问层的增强支持。它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。

在相当长的一段时间内,实现应用程序的数据访问层一直很麻烦。必须编写太多样板代码来执行简单查询以及执行分页和审计。Spring Data JPA旨在通过减少实际需要的工作量来显着改善数据访问层的实现。作为开发人员,您编写存储库接口,包括自定义查找器方法,Spring将自动提供实现。

Spring Data存储库抽象中的中央接口是Repository。它将域类以及域类的ID类型作为类型参数进行管理。此接口主要用作标记接口,用于捕获要使用的类型,并帮助您发现扩展此接口的接口。该CrudRepository规定对于正在管理的实体类复杂的CRUD功能。

public interface CrudRepository extends Repository {
     S save(S var1);

     Iterable saveAll(Iterable var1);

    Optional findById(ID var1);

    boolean existsById(ID var1);

    Iterable findAll();

    Iterable findAllById(Iterable var1);

    long count();

    void deleteById(ID var1);

    void delete(T var1);

    void deleteAll(Iterable var1);

    void deleteAll();
}

这个接口实现了对数据库实体的增删改查,通过对该接口的实现与扩展,可以非常方便的实现对数据库表的操作。

3、JPA-Java Persistence API,java持久性API

JPA (Java Persistence API) 是 Sun 官方提出的 Java 持久化规范。它为 Java 开发人员提供了一种对象/关联映射工具来管理 Java 应用中的关系数据。

JPA所维护的核心是entity,是通过一个持久化上下文来使用,包括下面三部分内容:

对象关系映射(ORM)支持注解或XML两种方式描述,springboot中通过注解实现;

entity操作API,对entity对象的crud操作,完成对象的持久化与查询;

查询语言,约定了JPQL(Java Persistence Query Language)java的类SQL查询语言,主体是entity对象。

4、关于spring.jpa.hibernate.ddl-auto 配置

Spring Boot 应用在启动过程中,就能根据实体,来自动映射成为数据库的表结构。这个选项在application属性文件中配置

  • validate 加载 Hibernate 时,验证创建数据库表结构
  • create 每次加载 Hibernate ,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。
  • create-drop 每次加载 Hibernate 时根据实体类创建表结构,退出后自动删除表结构
  • update 加载 Hibernate 自动更新数据库结构,没有就创建,有就更新为最新的实体结构

建议该选型配置为update。Spring Boot会根据是否认为您的数据库是嵌入式的,为您选择一个默认值。create-drop如果未检测到架构管理器或none在所有其他情况下,默认设置为create-drop。

三、详细操作步骤

1、创建数据库

docker run -d --rm --name mysqlserver -e MYSQL_ROOT_PASSWORD=123456 -e MYSQL_DATABASE=ipdb  -e TZ='Asia/Shanghai' -e MYSQL_ROOT_HOST="133.3.%" -p 3306:3306 mysqlutf8:v2

2、idea创建一个新的工程

使用spring initalizr向导创建工程

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第1张图片

 输入包名、项目名称,选择maven工程,输出为jar包springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第2张图片

 选择springboot的maven依赖包,至少包括web、jpa与mysqlspringboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第3张图片

在项目目录下新建三个目录controller、dao、entity 

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第4张图片

3、在pom.xml确认springboot依赖项

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第5张图片

4、编辑定义application.properties属性文件,定义项目运行环境

spring.datasource.url = jdbc:mysql://133.3.5.211:3306/ipdb
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.jpa.database = MYSQL
# 在控制台显示自动生成的sql语句
spring.http.log-request-details=true
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
# 命名策略 ,将实体类转换为数据库表名,字段为小写,当有大写字母的时候会转换为分隔符号“_”。
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# RDBMS 方言, 这里选用MySQL5Dialect
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

5、建立Ipbase实体类

import javax.persistence.*;
import javax.validation.constraints.NotNull;

@Entity
@Table(name = "ipbases")
public class Ipbase {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    @NotNull
    private String ipadd;
    @NotNull
    private String country;
    @NotNull
    private String privince;
    @NotNull
    private String city;
    @NotNull
    private String isp;

    public Ipbase() {
        super();
    }

    public Ipbase(@NotNull String ipadd, @NotNull String country, @NotNull String privince, @NotNull String city, @NotNull String isp) {
        this.ipadd = ipadd;
        this.country = country;
        this.privince = privince;
        this.city = city;
        this.isp = isp;
    }

    @Override
    public String toString() {
        return "Ipbase{" +
                "id=" + id +
                ", ipadd='" + ipadd + '\'' +
                ", country='" + country + '\'' +
                ", privince='" + privince + '\'' +
                ", city='" + city + '\'' +
                ", isp='" + isp + '\'' +
                '}';
    }

{set and get ......}

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第6张图片

创建完实体类就可以执行查看实体类自动在数据库中建表的效果

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第7张图片

通过mysql登陆进数据库查看数据库中内容

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第8张图片

 @GeneratedValue(strategy = GenerationType.IDENTITY) 当ID字段的注释为IDENTITY类型时,数据库只生成一张实体类表格,如果数据库不支持这类字段比如oracle数据库时,就需要选择另外一种注释方法,@GeneratedValue(strategy = GenerationType.AUTO),此时如上图所示系统会自动产生两张表格,其中一张hibernate_sequence表格类似oracle的序列专门配合生成id序列号使用。

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第9张图片

6、创建一个IpbaseDao的实体化接口实现接口,继承CrudRespositroy接口后再做一些个性化实现即可

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第10张图片

import javax.transaction.Transactional;
import java.util.List;

@Transactional
public interface IpbaseDao extends CrudRepository {
    public Ipbase findByIpadd(String ipadd);
    @Override
    List findAll();
}

我定义的ipbasedao接口扩展了crudrepository接口,原接口定义的两个泛型类型是实体类及其主键的类型,本例中实体类是Ipbase,主键ID是LONG类型。 这是一个神奇的接口,它提供所有CRUD实现。您无需在任何地方实现此接口。相反,Spring Boot将为您提供实现。

Create, read, update and delete (CRUD)针对数据库的增删改查自动搞定。

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第11张图片

可以扩展CrudRepository,您只需添加一个新方法findAll返回一个列表。如下例:

@Repository
public interface DataRepository extends CrudRepository {

    @Override
    List findAll();

}

如果您有一个“抽象”存储库要由所有存储库扩展,您也可以添加此方法,因此它将对您的所有存储库生效。如下例:

@NoRepositoryBean
public interface GenericRepository extends CrudRepository {

    @Override
    List findAll();

}

 7、在controller目录下新建一个控制类ipcontroller.java

import com.ipbase.info.dao.IpbaseDao;
import com.ipbase.info.entity.Ipbase;
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.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
public class ipcontroller {
@Autowired
IpbaseDao ipbaseDao;


@RequestMapping(value = "/add", produces = "text/html;charset=UTF-8", method = RequestMethod.GET)
public String addip(String ipadd, String country, String privince, String city, String isp, HttpServletRequest request) {
String ipId = "";
try {
Ipbase ipbase = new Ipbase(ipadd, country, privince, city, isp);
ipbaseDao.save(ipbase);
ipId = String.valueOf(ipbase.getId());
} catch (Exception ex) {
return "Add Ip Error:" + ex.toString();
}
return "Succesfully Add Ip Info with id=" + ipId;
}

@RequestMapping(value = "/getipinfo", produces = "text/html;charset=UTF-8", method = RequestMethod.GET)
public String findip(String ip, HttpServletRequest request) {
Ipbase ipbase = null;
try {
if (ip != null) {
ipbase = ipbaseDao.findByIpadd(ip);
} else {
ipbase = ipbaseDao.findByIpadd(request.getRemoteAddr());
}
} catch (Exception ex) {
return ex.toString();
}
if (ipbase!=null){
return ipbase.toString();
} else {
return "对不起数据库中没有这个IP:"+ip;
}
}

8、按shift+f9键进行项目测试观察底部console窗口输出日志

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第12张图片

观察最后一行出现Started InfoApplication in 4.677 seconds (JVM running for 5.711)就表明项目启动成功

9、通过浏览器录入2条测试数据

http://133.3.5.71:8080/add?ipadd=133.3.5.71&country=%E4%B8%AD%E5%9B%BD&privince=%E6%B9%96%E5%8C%97&city=%E6%AD%A6%E6%B1%89&isp=%E7%94%B5%E4%BF%A1

10、通过数据库查看录入测试数据情况

springboot系列之二-使用JPA操作mysql数据开发REST-API风格程序_第13张图片

11、通过浏览器进行REST风格查询IP地址

a、查询指定ip地址

http://133.3.5.71:8080/getipinfo?ip=202.103.44.150

b、不指定参数查询访问IP地址

http://133.3.5.71:8080/getipinfo

c、查询一个数据库中不存在的IP地址

http://133.3.5.71:8080/getipinfo?ip=1.1.1.1

四、总结回顾

     有两年没有碰java开发了,在本次springboot的jpa开发过程中,又找回了一点感觉,觉得使用spring-boot-starter-data-jpa开发数据库应用真的比以前从entity-dao-services-controller简单了很多,以前开发中还需要自己手工建表,现在通过对entity的调整自动解决与数据库的交互问题,非常方便。

下图是执行查询过程中,日志输出的hibernate自动为我们生成的sql语句,方便我们排查故障,如果不想输出这些语句,可以通过spring.http.log-request-details=false来关闭。

 

你可能感兴趣的:(微服务学习,容器云学习)