用IDEA創建基於Spring Cloud的Feign的微服務:服務接口、服務提供者、服務使用者分離

IDEA社區版本2019.3 , 用來創建接口包時需要做些額外操作。這裏使用Eureka作爲服務註冊中心,整個系統結構如下:

業務層與邏輯服務層
業務層 VA-DICTATION-RT-BUS 引入接口,使用服務
服務層 VA-SERVICES-LOCATION 引入接口,實現服務
數據層

MYSQL

創建T_LOCATION表

相關步驟如下:

1、MYSQL:創建t_location表

CREATE TABLE `t_location` (
  `f_id` int(11) NOT NULL AUTO_INCREMENT,
  `f_userid` varchar(64) NOT NULL,
  `f_create_time` datetime NOT NULL ON UPDATE CURRENT_TIMESTAMP,
  `f_type` int(11) unsigned zerofill NOT NULL COMMENT '1、微信上報;2、用戶上報',
  `f_latitude` float NOT NULL,
  `f_longtitude` float NOT NULL,
  `f_precision` float DEFAULT NULL COMMENT '微信上報時設置的:精度',
  `f_scale` float DEFAULT NULL COMMENT '用戶上報時設置的:放大比例尺',
  `f_lable` varchar(255) DEFAULT NULL COMMENT '用戶上報時設置的:poi',
  PRIMARY KEY (`f_id`),
  UNIQUE KEY `unique_index` (`f_userid`,`f_create_time`,`f_type`) USING BTREE,
  KEY `index_userid` (`f_userid`,`f_create_time`) USING BTREE,
  KEY `index_scope` (`f_latitude`,`f_longtitude`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=104 DEFAULT CHARSET=utf8

2、IDEA創建服務接口項目,發佈到本地Maven,供其他系統通過座標引用。

接口項目主要三個文件,第一個是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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.6.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>cn.net.mysoft.va.service.api</groupId>
	<artifactId>service-api</artifactId>
	<version>1.0.0</version>
	<!-- 
        這裏省略了,按你自己的項目來
        .......
    -->

	<build>
		<plugins>
			<!-- 這個打包的jar,不能被其他項目引用,對於接口包來說簡直無用
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
			-->

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<configuration>
					<source>1.8</source> <!--指明源碼用的Jdk版本-->
					<target>1.8</target> <!--指明打包後的Jdk版本-->
				</configuration>
			</plugin>
		</plugins>
	</build>

</project>

第二個是t_location對應的實體類

package cn.net.mysoft.va.service.api.location;

public class LocationEntity {
    int f_id;
    String f_userid;
    String f_create_time;
    int f_type;
    float f_latitude;
    float f_longtitude;
    float f_precision;
    float f_scale;
    String f_lable;

    public void setF_scale(float f_scale) {
        this.f_scale = f_scale;
    }

    public int getF_type() {
        return f_type;
    }

    public void setF_type(int f_type) {
        this.f_type = f_type;
    }

    public void setF_latitude(float f_latitude) {
        this.f_latitude = f_latitude;
    }

    public void setF_longtitude(float f_longtitude) {
        this.f_longtitude = f_longtitude;
    }

    public float getF_longtitude() {
        return f_longtitude;
    }

    public void setF_precision(float f_precision) {
        this.f_precision = f_precision;
    }

    public float getF_precision() {
        return f_precision;
    }

    public float getF_scale() {
        return f_scale;
    }

    public float getF_latitude() {
        return f_latitude;
    }

    public void setF_create_time(String f_create_time) {
        this.f_create_time = f_create_time;
    }

    public String getF_create_time() {
        return f_create_time;
    }

    public String getF_userid() {
        return f_userid;
    }

    public String getF_lable() {
        return f_lable;
    }

    public void setF_userid(String f_userid) {
        this.f_userid = f_userid;
    }

    public void setF_lable(String f_lable) {
        this.f_lable = f_lable;
    }

    public void setF_id(int f_id) {
        this.f_id = f_id;
    }

    public int getF_id() {
        return f_id;
    }

    @Override
    public String toString() {
        return "LocationEntity{" +
                "f_id=" + f_id +
                ", f_userid='" + f_userid + '\'' +
                ", f_create_time='" + f_create_time + '\'' +
                ", f_type=" + f_type +
                ", f_latitude=" + f_latitude +
                ", f_longtitude=" + f_longtitude +
                ", f_precision=" + f_precision +
                ", f_scale=" + f_scale +
                ", f_lable='" + f_lable + '\'' +
                '}';
    }
}

第三個,基於Feign的服務接口定義類

package cn.net.mysoft.va.service.api.location;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient("VA-SERVICES-LOCATION")
// VA-SERVICES-EXERCISE 部署到tomcat的包名
@RequestMapping("/location")
public interface LocationService {
    @RequestMapping(value = "/get/{uid}",method = RequestMethod.GET)
    String getByUid(@PathVariable("uid") String uid);

    /**
     * 這裏是個糟糕的設計,必須選擇application/json,參數纔會傳遞出去。但是會對參數做編碼,導致服務方無法解析。 需要先轉義
     * 後面嘗試使用text/html才搞定,與服務端的定義保持類一致
     * @param bodystr
     * @return
     */
    @RequestMapping(value = "/set",method = RequestMethod.POST,
            produces = {"text/html; charset=UTF-8"},
            consumes = "text/html;charset=UTF-8")
    String set(@RequestBody String bodystr);
}

3、IDEA基於嚮導建立Eureka服務,這裏沒有自定義安全與頁面,可不需要編碼,略。

4、編寫服務提供者模塊VA-SERVICES-LOCATION

第一步,修改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>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.5.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>cn.net.mysoft.va.services</groupId>
	<artifactId>va-serivices</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>va-serivices</name>
	<description>va service for location,user,account...</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
	</properties>

	<dependencies>
		<!-- ...... -->

		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.2</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>


		<dependency>
			<groupId>cn.net.mysoft.va.service.api</groupId>
			<artifactId>service-api</artifactId>
			<version>1.0.0</version>
		</dependency>

	</dependencies>

第二步,基本是Mybatis的工作,這裏直接上代碼

Mapper文件:

<?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="cn.net.mysoft.va.services.location.LocationDao">


    <select id="getByUid" resultType="cn.net.mysoft.va.service.api.location.LocationEntity"  parameterType="String">
        select f_id,
        f_userid,
        f_create_time,
        f_type,
        f_latitude,
        f_longtitude,
        f_precision,
        f_scale,
        f_lable

        from t_location a
        <where>
            a.f_userid=#{uid}
        </where>
        order by f_create_time desc limit 100
    </select>

    <insert id="insert"  parameterType="cn.net.mysoft.va.service.api.location.LocationEntity" keyProperty="f_id" useGeneratedKeys="true">
        INSERT INTO t_account (
        f_userid,
        f_create_time,
        f_type,
        f_latitude,
        f_longtitude,
        f_precision,
        f_scale,
        f_lable
        )
        VALUES
        (
        #{f_userid},
        now(),
        #{f_type},
        #{f_latitude},
        #{f_longtitude},
        #{f_precision},
        #{f_scale},
        #{f_lable}

        );
    </insert>
    <!--
        <update id="updateBalance" parameterType="cn.net.mysoft.va.dictation.services.exercise.mysql.account.AccountEntity">
            update t_account a set
            a.f_balance =  #{balance},
            a.f_modify_time=#{modifyTime},
            a.f_ver=#{ver}+1,
            a.f_sign=#{sign}
            <where>
                a.f_userid=#{userId} and a.f_ver=#{ver}
            </where>
        </update>
        -->
</mapper>

Dao文件:

package cn.net.mysoft.va.services.location;

import cn.net.mysoft.va.service.api.location.LocationEntity;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;


import java.util.List;

@Mapper
public interface LocationDao {
    int insert(LocationEntity itm);
    List<LocationEntity> getByUid(@Param("uid")String uid);
}

第三步,實現接口LocationService

package cn.net.mysoft.va.services.location;

import cn.net.mysoft.va.service.api.commonlib.RequestMessage;
import cn.net.mysoft.va.service.api.commonlib.ResponseMessage;
import cn.net.mysoft.va.service.api.location.LocationEntity;
import cn.net.mysoft.va.service.api.location.LocationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class LocationServiceImpl implements LocationService {
    @Autowired
    LocationDao objLocationDao;
    public static final Logger logger =  LoggerFactory.getLogger("va_servies_log");

    @Override
    public String getByUid(String uid) {
        logger.info("..."+uid);
        List<LocationEntity> lstLocationEntity =  objLocationDao.getByUid(uid);

        if(lstLocationEntity == null)
            return ResponseMessage.toJsonString(new ResponseMessage(-1,"db null"));

        return ResponseMessage.toJsonString(new ResponseMessage(0,"ok",lstLocationEntity));
    }

    @Override
    public String set(String bodystr) {
        logger.info("...");
        // parse from request body :
        RequestMessage<LocationEntity> objRequestMessage =
                RequestMessage.fromJsonString(bodystr,LocationEntity.class);


        if(objRequestMessage == null) {
            return ResponseMessage.toJsonString(new ResponseMessage(-1, "paras invalid"));
        }

        if(objRequestMessage.getMapParas().size() < 1)
            return ResponseMessage.toJsonString(new ResponseMessage(-1,"one or more record data should be provided."));

        int iRowCount = 0;
        for(LocationEntity itm:objRequestMessage.getMapParas().values()){
            logger.info("...");
            iRowCount += objLocationDao.insert(itm);
        }

        return ResponseMessage.toJsonString(new ResponseMessage(0,"Insert record number is :"+iRowCount));

    }
}

這裏有兩個打包文件(應該採用自定義配置,與Feign進一步集成),有需要的可加QQ(7457222)留言,交流。

第四步,配置文件properties,編譯後,註冊到Eureka。

# Eureka服務註冊中心的地址,用於client與server進行交流
eureka.client.service-url.defaultZone=http://127.0.0.1:8761/eureka/
# 用ip註冊進系統,這兩個很必需
eureka.instance.hostname=location-service
eureka.instance.preferIpAddress=true

# InstanceId採用了隨機數,確保了獨一無二
eureka.instance.instance-id=${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}


# 服務名
spring.application.name=va-services-location

# 提供者的服務端口
#server.port=8081

5、在服務使用方VA-DICTATION-RT-BUS調用

第一步,修改pom.xml,增加對接口的引用

<!-- 增加用戶與賬戶接口定義模塊 -->
		<dependency>
			<groupId>cn.net.mysoft.va.service.api</groupId>
			<artifactId>service-api</artifactId>
			<version>1.0.0</version>
		</dependency>

第二步,在入口類添加註解

@EnableFeignClients(basePackages = {"other.api","cn.net.mysoft.va.service.api"})

第三步,調用

	@Test
	void locationAPI2Service(){
		try {
			String res = objLocationService.getByUid("owrjxwq3Dt1Q-VMHZG4Absj6xIGc");
			System.out.println(res);

		}catch(Exception exp){
			System.out.println(exp.getMessage());
		}
	}

以上,如果有不通,或者優化建議,歡迎留言。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章