4.5 创建服务提供者
- 服务提供者是提供服务的节点,提供者整体结构
- 在父工程下创建一个名为 microservice-cloud-provider-dept-8001 的 Spring Boot Module,并在其 pom.xml 中引入以下依赖。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--引入父工程pom-->
<parent>
<artifactId>spring-cloud-microservice</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<groupId>com.example</groupId>
<artifactId>microservice-cloud-provider-dept-8001</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>microservice-cloud-provider-dept-8001</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--引入公共子模块-->
<dependency>
<groupId>org.example</groupId>
<artifactId>microservice-cloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<!--Spring Boot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--devtools 开发工具-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!--mysql 驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--整合 mybatis -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<!--spring-boot test 测试只能在test包中测试-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--junit 测试-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<!-- 修改后立即生效,热部署 这个热部署重启得更快 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.8.RELEASE</version>
</dependency>
<!--日志-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<!--jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 在 microservice-cloud-provider-dept-8001 类路径(/resources 目录)下,添加配置文件 application.yml,配置内容如下。
server:
port: 8001
spring:
application:
name: microservice-cloud-provider-dept-8001 #微服务名称,对外暴漏的微服务名称,十分重要
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/springcloud_db_core?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimeZone=UTC
type: com.alibaba.druid.pool.DruidDataSource
#SpringBoot默认是不注入这些的,需要自己绑定
#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:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许报错,java.lang.ClassNotFoundException: org.apache.Log4j.Priority
#则导入log4j 依赖就行
filters: stat,wall,log4j2
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#整合mybatis
mybatis:
type-aliases-package: com.zk.springcloud.entity
mapper-locations: classpath:mybatis/mapper/*.xml
#config-location: classpath:mybatis/mybatis-config.xml
configuration:
map-underscore-to-camel-case: true #默认开启驼峰命名法,可以不用设置该属性
注意:数据源中的url不需要对:进行转义
- 在 com.example.mapper包下创建一个名为 DeptMapper 的接口,代码如下。
package com.example.mapper;
import com.zk.springcloud.entity.Dept;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface DeptMapper {
boolean addDept(Dept dept);
//根据主键获取数据
Dept queryDeptByID(Integer deptNo);
//获取表中的全部数据
List<Dept> queryAll();
}
- 在 resources/mybatis/mapper/ 目录下,创建一个名为 DeptMapper.xml 的 MyBatis 映射文件,配置内容如下。
<?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.mapper.DeptMapper">
<resultMap id="BaseResultMap" type="Dept">
<id column="dept_no" property="deptNo" jdbcType="Integer"/>
<result column="dept_name" property="deptName" jdbcType="VARCHAR"/>
<result column="db_source" property="dbSource" jdbcType="VARCHAR"/>
</resultMap>
<sql id="Base_Column_List">
dept_no,dept_name,db_source
</sql>
<insert id="addDept" parameterType="Dept">
INSERT INTO springcloud_db_core.dept(dept_name,db_source)
VALUES(#{deptName},DATABASE())
</insert>
<select id="queryDeptByID" parameterType="java.lang.Integer" resultMap="BaseResultMap">
select <include refid="Base_Column_List"></include> from springcloud_db_core.dept
where dept_no =#{deptNo,jdbcType=INTEGER}
</select>
<select id="queryAll" resultMap="BaseResultMap">
select * from springcloud_db_core.dept
</select>
</mapper>
问题:将jdbcType="Integer"类型写为小写的类型
即是Mapper.xml文件出错,因为在mybatis的JdbcType枚举类中找不到一个叫Integer的枚举常量
- 解决方式:
连续按两次Shift键,开启IDEA的全局搜索,并搜索JdbcType,查找给定的常量。
结果发现给定的枚举常量为INTEGER,而不是Integer
将Mapper.xml中所有的jdbcType=“Integer”,改为jdbcType="INTEGER"大写的类型即可成功解决
<resultMap id="BaseResultMap" type="Dept"> <id column="dept_no" property="deptNo" jdbcType="INTEGER"/> <result column="dept_name" property="deptName" jdbcType="VARCHAR"/> <result column="db_source" property="dbSource" jdbcType="VARCHAR"/> </resultMap> <select id="queryDeptByID" parameterType="java.lang.Integer" resultMap="BaseResultMap"> select <include refid="Base_Column_List"></include> from springcloud_db_core.dept where dept_no =#{deptNo,jdbcType=INTEGER} </select>
package org.apache.ibatis.type;
import java.sql.Types;
import java.util.HashMap;
import java.util.Map;
/**
* @author Clinton Begin
*/
public enum JdbcType {
/*
* This is added to enable basic support for the
* ARRAY data type - but a custom type handler is still required
*/
ARRAY(Types.ARRAY),
BIT(Types.BIT),
TINYINT(Types.TINYINT),
SMALLINT(Types.SMALLINT),
INTEGER(Types.INTEGER),
BIGINT(Types.BIGINT),
FLOAT(Types.FLOAT),
REAL(Types.REAL),
DOUBLE(Types.DOUBLE),
NUMERIC(Types.NUMERIC),
DECIMAL(Types.DECIMAL),
CHAR(Types.CHAR),
VARCHAR(Types.VARCHAR),
LONGVARCHAR(Types.LONGVARCHAR),
DATE(Types.DATE),
TIME(Types.TIME),
TIMESTAMP(Types.TIMESTAMP),
BINARY(Types.BINARY),
VARBINARY(Types.VARBINARY),
LONGVARBINARY(Types.LONGVARBINARY),
NULL(Types.NULL),
OTHER(Types.OTHER),
BLOB(Types.BLOB),
CLOB(Types.CLOB),
BOOLEAN(Types.BOOLEAN),
CURSOR(-10), // Oracle
UNDEFINED(Integer.MIN_VALUE + 1000),
NVARCHAR(Types.NVARCHAR), // JDK6
NCHAR(Types.NCHAR), // JDK6
NCLOB(Types.NCLOB), // JDK6
STRUCT(Types.STRUCT),
JAVA_OBJECT(Types.JAVA_OBJECT),
DISTINCT(Types.DISTINCT),
REF(Types.REF),
DATALINK(Types.DATALINK),
ROWID(Types.ROWID), // JDK6
LONGNVARCHAR(Types.LONGNVARCHAR), // JDK6
SQLXML(Types.SQLXML), // JDK6
DATETIMEOFFSET(-155), // SQL Server 2008
TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE), // JDBC 4.2 JDK8
TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE); // JDBC 4.2 JDK8
public final int TYPE_CODE;
private static Map<Integer,JdbcType> codeLookup = new HashMap<>();
static {
for (JdbcType type : JdbcType.values()) {
codeLookup.put(type.TYPE_CODE, type);
}
}
JdbcType(int code) {
this.TYPE_CODE = code;
}
public static JdbcType forCode(int code) {
return codeLookup.get(code);
}
}
- 在 resources/mybatis/目录下,创建一个名为mybatis-config.xml 的 MyBatis 配置文件,配置内容如下。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!--只保留两项,setting,typeAliases-->
<settings>
<!--全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。默认开启true-->
<!--显示的定义出来是为了代码可读性-->
<setting name="cacheEnabled" value="true"/>
</settings>
</configuration>
- 在 com.example.service包下创建一个名为 DeptService 的接口,代码如下。接口中默认是public abstract
package com.example.service;
import com.zk.springcloud.entity.Dept;
import java.util.List;
public interface DeptService {
boolean addDept(Dept dept);
//根据主键获取数据
Dept queryDeptByID(Integer deptNo);
//获取表中的全部数据
List<Dept> queryAll();
}
- 在 com.example.service包下创建 DeptService 接口的实现类 DeptServiceImpl,代码如下。
package com.example.service;
import com.example.mapper.DeptMapper;
import com.zk.springcloud.entity.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author CNCLUKZK
* @create 2022/9/7-1:42
*/
@Service
public class DeptServiceImpl implements DeptService{
@Autowired
private DeptMapper deptMapper;
@Override
public boolean addDept(Dept dept) {
return deptMapper.addDept(dept);
}
@Override
public Dept queryDeptByID(Integer deptNo) {
return deptMapper.queryDeptByID(deptNo);
}
@Override
public List<Dept> queryAll() {
return deptMapper.queryAll();
}
}
- 在 com.example.controller 包下创建一个名为 DeptController 的 Controller 类,代码如下。
package com.example.controller;
import com.example.service.DeptService;
import com.zk.springcloud.entity.Dept;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author CNCLUKZK
* @create 2022/9/7-1:43
*/
@RestController //提供restful服务,@RestController需要spring-boot-starter-web
//@Slf4j
@RequestMapping("/dept")
public class DeptController {
@Autowired
private DeptService deptService;
@PostMapping("/add") //GET跟安不安全没关系的,RESTful规范问题
public boolean addDept(@RequestBody Dept dept) {
return deptService.addDept(dept);
}
@GetMapping("/get/{deptNo}")
public Dept getDeptByID(@PathVariable("deptNo") Integer deptNo) {
return deptService.queryDeptByID(deptNo);
}
@GetMapping("/list")
public List<Dept> queryAll() {
return deptService.queryAll();
}
}
- 然后,启动microservice-cloud-provider-dept-8001项目的启动类,测试运行
- 访问http://127.0.0.1:8001/dept/get/1结果:
- 访问http://127.0.0.1:8001/dept/list
- 说明microservice-cloud-provider-dept-8001项目运行正常
开发期间存在的问题1:Spring Boot项目中含有Mybatis,打Jar包运行之后,报如下错误.
Failed to configure a DataSource: ‘url’ attribute is not specified and no embedded datasource could be configured.
Reason: Failed to determine a suitable driver class
- 解决方式:
问题原因:Mybatis没有找到合适的驱动,即spring :datasource:url没有加载成功
- DataSourceAutoConfiguration会自动加载.
- spring :datasource:url 属性配置有误,如地址格式有问题
- spring :datasource:url属性配置所在的yml,properties文件没有被加载
@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class})
解决方式2:在application.properties/或者application.yml文件中配置正确的数据库信息,在spring.xml配置文件中引用了数据库地址 所以需要对:等进行转义处理.但是在application.properties/或者application.yml文件并不需要转义
spring:
application:
name: microservice-cloud-provider-dept-8001
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
url: jdbc:mysql://localhost:3306/springcloud_db_core?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimeZone=UTC
type: com.alibaba.druid.pool.DruidDataSource
//错误示例
spring.datasource.url = jdbc:mysql\://localhost\:3306/springcloud_db_core?useSSL=true&useUnicode=true&characterEncoding=utf-8&serverTimeZone=UTC
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
问题2:新导入项目,提示报 Cannot access org.springframework.context.ConfigurableApplicationContext的错
-
- 解决办法1:需删除导入项目自动生成的xxx.iml ,然后刷新下右侧maven tab即可
- 若找不到Maven这个tab,可以通过help下的Find Action,在搜索框中搜索Maven
- 解决办法2:若删除删除xxx.iml 后模块 pom变成了灰色并有删除线,需要添加模块的pom.xml,具体是先看Module是否报错,没错时点击“+”add maven project
- 在弹框中选择模块自己的pom.xml文件,然后刷新一下即可解决问题,额外注意下子模块的变动引起的父工程的变化。