SpringCloud微服務完整例項
一微服務架構概述
1.1 微服務特性以及優點
- 每個服務可以獨立執行在自己的程序裡
- 一系列獨立執行的微服務(goods,order,pay,user,search…)共同構建了整個系統
- 每個服務為獨立的業務開發,一個微服務只關注某個特定的功能,例如使用者管理,商品管理微服務
- 微服務之間通過一些輕量級的通訊機制進行通訊,例如通過Restful API進行呼叫
- 技術棧不受限:可以使用不同的開發語言和資料儲存技術
- 全自動的部署機制
- 按需伸縮:根據需求和應用場景,實現細粒度的水平擴充套件
1.2 微服務帶來的挑戰
- 運維要求較高
- 分散式的複雜性
- 介面調整成本較高
1.3 微服務設計原則
- 單一職責原則
- 服務自治原則
- 輕量級通訊機制
- 微服務粒度
1.4 微服務開發框架
- SpringCloud:眾多元件構造完善的分散式系統
- Dubbo/Dubbox:關注服務治理
- Dropwizard:關注單個微服務開發
二 SpringCloud概述與開發環境
2.1 SpringCloud概述
SpringCloud是基於SpringBoot之上的用來快速構建微服務系統的工具集,擁有功能完善的輕量級微服務元件,例如服務治理(Eureka),宣告式REST呼叫(Feign),客戶端負載均衡(Ribbon),服務容錯(Hystrix),服務閘道器(Zuul)以及服務配置(Spring Cloud Config),服務跟蹤(Sleuth)等等。
官網連結:http://projects.spring.io/spring-cloud/
目前主流的版本為SpringBoot1.4.5.RELEAE和SpringCloudCamden.SR7,
Maven pom配置如下:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.4.5.RELEASE</version> </parent> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Camden.SR7</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId></groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId></groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> </dependencies>
2.2 開發環境
MacOS10.12+JDK8u131+IntelliJ IDEA2017.1.4
Tomcat8.5+Maven3.3.9+Git2.12+Firefox54
Spring4.3.9.RELEASE+SpringBoot1.4.5.RELEASE+SpringCloud Camden.SR7
三 工程機器模組說明
3.1 工程說明
工程首先自定義了Maven父工程,其中定義如下的公共元件:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 自定義工程的maven座標-->
<groupId>com.ekeyfund.springcloud</groupId>
<artifactId>springcloud-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- 基於SpringBoot 1.4.5.RELEASE-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.5.RELEASE</version>
<relativePath/>
</parent>
<!-- 定義引用類庫版本 -->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Camden.SR7</spring-cloud.version>
<springcloud-parent.version>2.0.0-SNAPSHOT</springcloud-parent.version>
<druid.version>1.0.31</druid.version>
<jackson.version>2.8.8</jackson.version>
<commons-lang3.version>3.5</commons-lang3.version>
<ehcache.version>3.1.4</ehcache.version>
<hibernate.version>5.0.12.Final</hibernate.version>
<servlet-api.version>3.1.0</servlet-api.version>
<commons-collection4.version>4.1</commons-collection4.version>
<springframework.oxm.version>4.3.9.RELEASE</springframework.oxm.version>
</properties>
<!-- 引入SpringCloud微服務常用元件-->
<modules>
<module>springcloud-eureka-server</module>
<module>springcloud-eureka-server-ha</module>
<module>springcloud-provider-user-service</module>
<module>springcloud-consumer-h5-ribbon-hystrix</module>
<module>springcloud-consumer-h5-feign</module>
<module>springcloud-api-gateway</module>
<module>springcloud-consumer-h5</module>
<module>springcloud-config-server</module>
</modules>
<dependencies>
<!-- 服務發現元件-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
<!-- 應用監控-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 應用測試-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid.version}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet-api.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>${commons-collection4.version}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>${hibernate.version}</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>${ehcache.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${springframework.oxm.version}</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
3.2 模組說明
模組則藉助IntelliJ IDEA結合Spring Initializer自動生成工程結構,主要模組和說明如下:
四 使用SpringBoot實現服務提供者
所屬maven模組:springcloud-provider-user-service
基於SpringBoot的Web和JPA模組實現Restful API的常用方法
4.1 entity
主要包含User,Role,Department三個實體
Role.java
package com.ekeyfund.springcloud.entity;
import javax.persistence.*;
import java.io.Serializable;
/**
* Role Entity
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:36
*/
@Entity
@Table(name = "springboot_role")
public class Role implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "role_id")
private Long id;
@Column(name = "role_name")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return new org.apache.commons.lang3.builder.ToStringBuilder(this)
.append("id", id)
.append("name", name)
.toString();
}
}
Department.java
package com.ekeyfund.springcloud.entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.io.Serializable;
/**
* Department Entity
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:31
*/
@Entity
@Table(name = "springboot_department")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Department implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "department_id")
private Long id;
@Column(name = "department_name")
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.toString();
}
}
User.java
package com.ekeyfund.springcloud.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.format.annotation.DateTimeFormat;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
/**
* User Entity
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:32
*/
@Entity
@Table(name = "springboot_user")
public class User implements Serializable{
@Id
@Column(name = "user_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "user_name")
private String name;
@Column(name = "user_password")
private String password;
@Column(name = "user_create_date")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
@ManyToOne
@JoinColumn(name = "department_id")
@JsonBackReference
private Department department;
@ManyToMany(cascade = {},fetch = FetchType.EAGER)
@JoinTable(name = "springboot_user_role",joinColumns = {@JoinColumn(name="user_id")},
inverseJoinColumns = {@JoinColumn(name = "role_id")}
)
private List<Role> roleList;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.append("password", password)
.append("createDate", createDate)
.append("department", department)
.append("roleList", roleList)
.toString();
}
}
4.2 資料訪問Repository
主要包含UserRepository和DepartmentRepository
DepartmentRepository.java
package com.ekeyfund.springcloud.repository;
import com.ekeyfund.springcloud.entity.Department;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* Created by tony on 2017/6/19.
*/
@Repository
public interface DepartmentRepository extends JpaRepository<Department,Long> {
}
UserRepoistory.java
package com.ekeyfund.springcloud.repository;
import com.ekeyfund.springcloud.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Collection;
import java.util.Date;
import java.util.List;
/**
* User Repository
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:54
*/
@Repository
public interface UserRepository extends JpaRepository<User,Long>{
/**
* and
* @param id
* @param name
* @return
*/
User findByIdAndName(Long id, String name);
User findByNameAndPassword(String name, String password);
/**
* or
* @param id
* @param name
* @return
*/
User findByIdOrName(Long id, String name);
/**
* between
* @param start
* @param end
* @return
*/
List<User> findByCreateDateBetween(Date start, Date end);
/**
* lessThan
* @param start
* @return
*/
List<User> getByCreateDateLessThan(Date start);
/**
* Greater Than
* @param start
* @return
*/
List<User> findByCreateDateGreaterThan(Date start);
/**
* is null
* @return
*/
List<User> findByNameIsNull();
/**
* in
* @param nameList
* @return
*/
List<User> findByNameIn(Collection<String> nameList);
}
4.3 業務邏輯Service
主要包含UserService,DepartmentService及其實現
UserService.java
package com.ekeyfund.springcloud.service;
import com.ekeyfund.springcloud.entity.User;
import java.util.List;
/**
* Created by tony on 2017/6/19.
*/
public interface UserService {
/**
* 登入
* @param name
* @param password
* @return
*/
public User login(String name, String password);
/**
* 註冊
* @param user
* @return
*/
public User register(User user);
/**
* 登出
* @param user
* @return
*/
void writeOff(User user);
/**
* 當前使用者是否已經存在
* @param user
* @return
*/
boolean isExists(User user);
List<User> getAllUser();
User getUserById(Long id);
}
UserServiceImpl.java
package com.ekeyfund.springcloud.service.impl;
import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.repository.UserRepository;
import com.ekeyfund.springcloud.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
/**
* User Service Impl
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午3:34
*/
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User login(String name, String password) {
return userRepository.findByNameAndPassword(name,password);
}
@Override
public User register(User user) {
return userRepository.save(user);
}
@Override
public void writeOff(User user) {
userRepository.delete(user);
}
@Override
public boolean isExists(User user) {
return userRepository.findOne(user.getId())!=null?true:false;
}
@Override
public List<User> getAllUser() {
return userRepository.findAll();
}
@Override
public User getUserById(Long id) {
return userRepository.findOne(id);
}
}
DepartmentService.java
package com.ekeyfund.springcloud.service;
import com.ekeyfund.springcloud.entity.Department;
/**
* Created by tony on 2017/6/19.
*/
public interface DepartmentService {
Department saveDepartment(Department department);
Department getDepartmentById(Long id);
}
DepartmentServiceImpl.java
package com.ekeyfund.springcloud.service.impl;
import com.ekeyfund.springcloud.entity.Department;
import com.ekeyfund.springcloud.repository.DepartmentRepository;
import com.ekeyfund.springcloud.service.DepartmentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
/**
* Department Impl
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午3:12
*/
@Transactional
@Service
public class DepartmentImpl implements DepartmentService {
@Autowired
private DepartmentRepository departmentRepository;
@Override
public Department saveDepartment(Department department) {
return departmentRepository.save(department);
}
@Override
public Department getDepartmentById(Long id) {
return departmentRepository.findOne(id);
}
}
4.4 Controller層
主要包含提供User完整的Restful API 的UserController
UserController.java
package com.ekeyfund.springcloud.controller;
import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.service.UserService;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* UserController
* Restful API
* @author Liuguanglei [email protected]
* @create 2017-06-下午11:24
*/
@RestController
public class UserController {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private UserService userService;
@GetMapping(value = "/list")
public List<User> list(){
ServiceInstance instance=discoveryClient.getLocalServiceInstance();
LOGGER.info("call user/list service host is "+instance.getHost()+"service_id is "+instance.getServiceId());
return userService.getAllUser();
}
@GetMapping(value = "/login")
public User login( @RequestParam String name,@RequestParam String password){
User user=userService.login(name,password);
return user;
}
@PostMapping("/register")
public String register(@ModelAttribute User user){
User result =userService.register(user);
return result!=null?"success":"fail";
}
@GetMapping("/get/{id}")
public User get(@PathVariable Long id){
return userService.getUserById(id);
}
@PutMapping("/update/{id}")
public String update(@PathVariable Long id,@ModelAttribute User user){
User updatedUser =userService.getUserById(id);
updatedUser.setName(user.getName());
updatedUser.setPassword(user.getPassword());
updatedUser.setCreateDate(new Date());
User result= userService.register(updatedUser);
return result!=null?"success":"fail";
}
@DeleteMapping("/delete/{id}")
public String delete(@PathVariable Long id){
User user =new User();
user.setId(id);
userService.writeOff(user);
return "success";
}
}
4.5 Configuration
主要包含資料來源Druid和JPA的配置
DruidConfiguation.java
package com.ekeyfund.springcloud.configuration;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
/**
* Druid Configuration
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午5:48
*/
public class DruidConfiguration {
@Bean
public ServletRegistrationBean statViewServle(){
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
//白名單:
servletRegistrationBean.addInitParameter("allow","192.168.1.218,127.0.0.1");
//IP黑名單 (存在共同時,deny優先於allow) : 如果滿足deny的即提示:Sorry, you are not permitted to view this page.
servletRegistrationBean.addInitParameter("deny","192.168.1.100");
//登入檢視資訊的賬號密碼.
servletRegistrationBean.addInitParameter("loginUsername","druid");
servletRegistrationBean.addInitParameter("loginPassword","12345678");
//是否能夠重置資料.
servletRegistrationBean.addInitParameter("resetEnable","false");
return servletRegistrationBean;
}
@Bean
public FilterRegistrationBean statFilter(){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
//新增過濾規則.
filterRegistrationBean.addUrlPatterns("/*");
//新增不需要忽略的格式資訊.
filterRegistrationBean.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return filterRegistrationBean;
}
}
JPAPersistenceConfiguration
package com.ekeyfund.springcloud.configuration;
import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.Properties;
/**
* JPA Persistence Configuration
*
* @author Liuguanglei [email protected]
* @create 2017-06-上午11:26
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
@EnableTransactionManagement(proxyTargetClass = true) //啟用JPA的事務管理
@EnableJpaRepositories(basePackages = "com.ekeyfund.springcloud.repository" )//啟用JPA資源庫並指定資源庫介面位置
@EntityScan(basePackages = "com.ekeyfund.springcloud.entity")//指定實體的位置
public class JPAPersistenceConfiguration {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(JPAPersistenceConfiguration.class);
/*******************資料庫和連線池配置資訊,讀取application.properties檔案的屬性值****************************/
@Value("${spring.datasource.driver-class-name}")
private String driverClass;
@Value("${spring.datasource.username}")
private String userName;
@Value("${spring.datasource.password}")
private String password;
@Value("${spring.datasource.url}")
private String url;
@Value("${spring.datasource.initialSize}")
private int initialSize;
@Value("${spring.datasource.minIdle}")
private int minIdle;
@Value("${spring.datasource.maxActive}")
private int maxActive;
@Value("${spring.datasource.maxWait}")
private long maxWait;
@Value("${spring.datasource.timeBetweenEvictionRunsMillis}")
private long timeBetweenEvictionRunsMillis;
@Value("${spring.datasource.minEvictableIdleTimeMillis}")
private long minEvictableIdleTimeMillis;
@Value("${spring.datasource.filters}")
private String filters;
@Value("${spring.datasource.connectionProperties}")
private String connectionProperties;
@Bean(name = "druidDataSource",initMethod = "init",destroyMethod = "close")
public DataSource dataSource(){
DruidDataSource druidDataSource =new DruidDataSource();
druidDataSource.setDriverClassName(driverClass);
druidDataSource.setUsername(userName);
druidDataSource.setPassword(password);
druidDataSource.setUrl(url);
druidDataSource.setInitialSize(initialSize);
druidDataSource.setMinIdle(minIdle);
druidDataSource.setMaxActive(maxActive);
druidDataSource.setMaxWait(maxWait);
druidDataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
druidDataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
druidDataSource.setConnectionProperties(connectionProperties);
try {
druidDataSource.setFilters(filters);
} catch (SQLException e) {
LOGGER.error("build datasoure exception ",e.getMessage());
}
return druidDataSource;
}
@Bean(name = "entityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource druidDataSource){
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean =new LocalContainerEntityManagerFactoryBean();
localContainerEntityManagerFactoryBean.setDataSource(druidDataSource);
localContainerEntityManagerFactoryBean.setPackagesToScan("com.ekeyfund.springcloud.entity");
localContainerEntityManagerFactoryBean.setJpaProperties(buildHibernateProperties());
localContainerEntityManagerFactoryBean.setJpaDialect(new HibernateJpaDialect());
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter(){
{
setDatabase(org.springframework.orm.jpa.vendor.Database.MYSQL);
setDatabasePlatform("org.hibernate.dialect.MySQL5Dialect");
}
});
return localContainerEntityManagerFactoryBean;
}
@Bean
public PlatformTransactionManager transactionManager(DataSource druidDataSource, EntityManagerFactory entityManagerFactory){
JpaTransactionManager jpaTransactionManager=new JpaTransactionManager();
jpaTransactionManager.setDataSource(druidDataSource);
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory);
return jpaTransactionManager;
}
@Bean
PersistenceExceptionTranslationPostProcessor persistenceExceptionTranslationPostProcessor(){
return new PersistenceExceptionTranslationPostProcessor();
}
protected Properties buildHibernateProperties(){
Properties hibernateProperties =new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("hibernate.hbm2ddl.auto","update");
hibernateProperties.setProperty("hibernate.show_sql", "false");
hibernateProperties.setProperty("hibernate.use_sql_comments", "false");
hibernateProperties.setProperty("hibernate.format_sql", "true");
hibernateProperties.setProperty("hibernate.generate_statistics", "false");
hibernateProperties.setProperty("javax.persistence.validation.mode", "none");
//Audit History flags
hibernateProperties.setProperty("org.hibernate.envers.store_data_at_delete", "true");
hibernateProperties.setProperty("org.hibernate.envers.global_with_modified_flag", "true");
hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", "true");
hibernateProperties.setProperty("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");
hibernateProperties.setProperty("hibernate.cache.use_query_cache", "true");
return hibernateProperties;
}
}
4.6 應用配置
主要包含springboot的application.properties,logback的logback-spring.xml以及快取框架的ehcache.xml
application.propeties
##DataSource Config
##\u6570\u636e\u5e93\u8fde\u63a5\u6c60\u4fe1\u606f\u914d\u7f6e
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/springboot?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=guanglei
# \u4e0b\u9762\u4e3a\u8fde\u63a5\u6c60\u7684\u8865\u5145\u8bbe\u7f6e\uff0c\u5e94\u7528\u5230\u4e0a\u9762\u6240\u6709\u6570\u636e\u6e90\u4e2d
# \u521d\u59cb\u5316\u5927\u5c0f\uff0c\u6700\u5c0f\uff0c\u6700\u5927
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# \u914d\u7f6e\u83b7\u53d6\u8fde\u63a5\u7b49\u5f85\u8d85\u65f6\u7684\u65f6\u95f4
spring.datasource.maxWait=60000
# \u914d\u7f6e\u95f4\u9694\u591a\u4e45\u624d\u8fdb\u884c\u4e00\u6b21\u68c0\u6d4b\uff0c\u68c0\u6d4b\u9700\u8981\u5173\u95ed\u7684\u7a7a\u95f2\u8fde\u63a5\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
spring.datasource.timeBetweenEvictionRunsMillis=60000
# \u914d\u7f6e\u4e00\u4e2a\u8fde\u63a5\u5728\u6c60\u4e2d\u6700\u5c0f\u751f\u5b58\u7684\u65f6\u95f4\uff0c\u5355\u4f4d\u662f\u6beb\u79d2
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# \u6253\u5f00PSCache\uff0c\u5e76\u4e14\u6307\u5b9a\u6bcf\u4e2a\u8fde\u63a5\u4e0aPSCache\u7684\u5927\u5c0f
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# \u914d\u7f6e\u76d1\u63a7\u7edf\u8ba1\u62e6\u622a\u7684filters\uff0c\u53bb\u6389\u540e\u76d1\u63a7\u754c\u9762sql\u65e0\u6cd5\u7edf\u8ba1\uff0c'wall'\u7528\u4e8e\u9632\u706b\u5899
spring.datasource.filters=stat,wall,log4j
# \u901a\u8fc7connectProperties\u5c5e\u6027\u6765\u6253\u5f00mergeSql\u529f\u80fd\uff1b\u6162SQL\u8bb0\u5f55
spring.datasource.connectionProperties=druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
# \u5408\u5e76\u591a\u4e2aDruidDataSource\u7684\u76d1\u63a7\u6570\u636e
#spring.datasource.useGlobalDataSourceStat=true
# druid \u8bbf\u95ee\u5730\u5740 http://host:port/druid/index.html
##Log Config
logging.config=classpath:logback-spring.xml
## SpringData JPA Config
spring.jpa.database=mysql
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
server.port=9996
ehcache.xml
<ehcache>
<!-- Sets the path to the directory where cache .data files are created.
If the path is a Java System Property it is replaced by
its value in the running VM.
The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
<!--
指定一個目錄:當 EHCache 把資料寫到硬碟上時, 將把資料寫到這個目錄下.
-->
<diskStore path="tempDirectory"/>
<!--Default Cache configuration. These will applied to caches programmatically created through
the CacheManager.
The following attributes are required for defaultCache:
maxInMemory - Sets the maximum number of objects that will be created in memory
eternal - Sets whether elements are eternal. If eternal, timeouts are ignored and the element
is never expired.
timeToIdleSeconds - Sets the time to idle for an element before it expires. Is only used
if the element is not eternal. Idle time is now - last accessed time
timeToLiveSeconds - Sets the time to live for an element before it expires. Is only used
if the element is not eternal. TTL is now - creation time
overflowToDisk - Sets whether elements can overflow to disk when the in-memory cache
has reached the maxInMemory limit.
-->
<!--
設定快取的預設資料過期策略
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
/>
<!--
設定具體的命名快取的資料過期策略。每個命名快取代表一個快取區域
快取區域(region):一個具有名稱的快取塊,可以給每一個快取塊設定不同的快取策略。
如果沒有設定任何的快取區域,則所有被快取的物件,都將使用預設的快取策略。即:<defaultCache.../>
Hibernate 在不同的快取區域儲存不同的類/集合。
對於類而言,區域的名稱是類名。如:com.ekeyfund.springboot.jpa.entity.User
對於集合而言,區域的名稱是類名加屬性名。如com.ekeyfund.springboot.jpa.entity.User.roleList
-->
<!--
name: 設定快取的名字,它的取值為類的全限定名或類的集合的名字
maxElementsInMemory: 設定基於記憶體的快取中可存放的物件最大數目
eternal: 設定物件是否為永久的, true表示永不過期,
此時將忽略timeToIdleSeconds 和 timeToLiveSeconds屬性; 預設值是false
timeToIdleSeconds:設定物件空閒最長時間,以秒為單位, 超過這個時間,物件過期。
當物件過期時,EHCache會把它從快取中清除。如果此值為0,表示物件可以無限期地處於空閒狀態。
timeToLiveSeconds:設定物件生存最長時間,超過這個時間,物件過期。
如果此值為0,表示物件可以無限期地存在於快取中. 該屬性值必須大於或等於 timeToIdleSeconds 屬性值
overflowToDisk:設定基於記憶體的快取中的物件數目達到上限後,是否把溢位的物件寫到基於硬碟的快取中
-->
<cache name="com.ekeyfund.springcloud.entity.Department"
maxElementsInMemory="1"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="true"
/>
<cache name="com.ekeyfund.springcloud.entity.User"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
<cache name="com.ekeyfund.springcloud.entity.Role"
maxElementsInMemory="1000"
eternal="true"
timeToIdleSeconds="0"
timeToLiveSeconds="0"
overflowToDisk="false"
/>
</ehcache>
logback.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--<include resource="org/springframework/boot/logging/logback/base.xml"/>-->
<!-- 專案的appid -->
<property name="APP_ID" value="SpringCloud-Provider-User-Service"/>
<property name="LOG_PATH" value="logs"></property>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg %n</pattern>
</encoder>
</appender>
<appender name="FILE_LOG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
</filter>
<file>${LOG_PATH}/${APP_ID}/access.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_DEBUG"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_debug.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_INFO"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_info.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_WARN"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_warn.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE_ERROR"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
<file>${LOG_PATH}/${APP_ID}/access_error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOG_PATH}/${APP_ID}/access_error.log.%d{yyyy-MM-dd}.zip
</fileNamePattern>
<maxHistory>10</maxHistory>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss} %-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日誌.預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改預設的佇列的深度,該值會影響效能.預設值為256 -->
<queueSize>512</queueSize>
<appender-ref ref="FILE_LOG"/>
</appender>
<appender name="ASYNC_LOG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日誌.預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改預設的佇列的深度,該值會影響效能.預設值為256 -->
<queueSize>512</queueSize>
<appender-ref ref="FILE_LOG"/>
</appender>
<appender name="ASYNC_LOG_DEBUG" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日誌.預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改預設的佇列的深度,該值會影響效能.預設值為256 -->
<queueSize>512</queueSize>
<appender-ref ref="FILE_DEBUG"/>
</appender>
<appender name="ASYNC_LOG_INFO" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日誌.預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改預設的佇列的深度,該值會影響效能.預設值為256 -->
<queueSize>512</queueSize>
<appender-ref ref="FILE_INFO"/>
</appender>
<appender name="ASYNC_LOG_WARN" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日誌.預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改預設的佇列的深度,該值會影響效能.預設值為256 -->
<queueSize>512</queueSize>
<appender-ref ref="FILE_WARN"/>
</appender>
<appender name="ASYNC_LOG_ERROR" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丟失日誌.預設的,如果佇列的80%已滿,則會丟棄TRACT、DEBUG、INFO級別的日誌 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改預設的佇列的深度,該值會影響效能.預設值為256 -->
<queueSize>512</queueSize>
<appender-ref ref="FILE_ERROR"/>
</appender>
<root level="INFO">
<!-- appender referenced after it is defined -->
<appender-ref ref="STDOUT"/>
<appender-ref ref="ASYNC_LOG"/>
<appender-ref ref="ASYNC_LOG_DEBUG"/>
<appender-ref ref="ASYNC_LOG_INFO"/>
<appender-ref ref="ASYNC_LOG_WARN"/>
<appender-ref ref="ASYNC_LOG_ERROR"/>
</root>
<logger name="org.springframework" level="INFO"/>
</configuration>
4.7 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-provider-user-service</artifactId>
<packaging>jar</packaging>
<name>springcloud-user-service</name>
<description>SpringCloud User Service Application</description>
<parent>
<groupId>com.ekeyfund.springcloud</groupId>
<artifactId>springcloud-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<start-class>com.ekeyfund.springcloud.SpringcloudUserServiceMasterApplication</start-class>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>${start-class}</mainClass>
<layout>ZIP</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
4.8 啟動類
package com.ekeyfund.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
//@EnableDiscoveryClient//啟用Eureka中的DiscoveryClient實現(自動化配置,建立DiscoveryClient介面針對Eureka客戶端的EurekaDiscoveryClient例項)
@SpringBootApplication
public class SpringcloudUserServiceMasterApplication {
public static void main(String[] args) {
SpringApplication.run(SpringcloudUserServiceMasterApplication.class, args);
}
}
4.9 測試用例
package com.ekeyfund.springcloud;
import com.ekeyfund.springcloud.entity.Department;
import com.ekeyfund.springcloud.entity.User;
import com.ekeyfund.springcloud.service.DepartmentService;
import com.ekeyfund.springcloud.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.Date;
@RunWith(SpringRunner.class)
@SpringBootTest
@ComponentScan("com.ekeyfund.springcloud")
public class SpringcloudUserServiceApplicationTests {
private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(SpringcloudUserServiceApplicationTests.class);
@Test
public void contextLoads() {
}
@Autowired
private DepartmentService departmentService;
@Autowired
private UserService userService;
@Test
public void testDepartmentService(){
Department department=new Department();
department.setName("dev");
Department result =departmentService.saveDepartment(department);
LOGGER.info("add result "+result);
Long id =1L;
result =departmentService.getDepartmentById(id);
LOGGER.info("get department "+result);
}
@Test
public void testUserRegister()throws Exception{
User user =new User();
user.setName("tony");
user.setPassword("666666");
user.setCreateDate(new Date());
Department department=departmentService.getDepartmentById(1L);
user.setDepartment(department);
User result =userService.register(user);
LOGGER.info("register result "+result);
}
@Test
public void testWriteOff()throws Exception{
User user =new User();
user.setName("tony");
user.setPassword("666666");
userService.writeOff(user);
}
@Test
public void testUserLogin()throws Exception{
User user =new User();
user.setName("tony");
user.setPassword("666666");
User result =userService.login(user.getName(),user.getPassword());
LOGGER.info("login "+result);
}
@Test
public void testUserIsExist()throws Exception{
User user =new User();
user.setId(4L);
boolean result =userService.isExists(user);
LOGGER.info("isExist "+result);
}
}
五 使用SpringBoot實現服務消費者
所屬maven模組:springcloud-consumer-h5
5.1 entity
主要包含User,Department,Role
Role.java
package com.ekeyfund.springcloud.entity;
/**
* Role Entity
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:36
*/
public class Role {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return new org.apache.commons.lang3.builder.ToStringBuilder(this)
.append("id", id)
.append("name", name)
.toString();
}
}
Department.java
package com.ekeyfund.springcloud.entity;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* Department Entity
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:31
*/
public class Department {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.toString();
}
}
User.java
package com.ekeyfund.springcloud.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import java.util.List;
/**
* User Entity
*
* @author Liuguanglei [email protected]
* @create 2017-06-下午2:32
*/
public class User {
private Long id;
private String name;
private String password;
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
@JsonBackReference
private Department department;
private List<Role> roleList;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
public List<Role> getRoleList() {
return roleList;
}
public void setRoleList(List<Role> roleList) {
this.roleList = roleList;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("name", name)
.append("password", password)
.append("createDate", createDate)
.append("department", department)
.append("roleList", roleList)
.toString();
}
}
5.2 Configuraiton
主要包含Spring MVC相關配置
MVCConfiguration.java
package com.ekeyfund.springcloud.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableWebMvc
public class MVCConfiguration extends WebMvcConfigurerAdapter{
/**
*
* @return
*/
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
RequestMappingHandlerAdapter requestMappingHandlerAdapter=new RequestMappingHandlerAdapter();
List<HttpMessageConverter<?>> messageConverters =new ArrayList<>();
messageConverters.add(mappingJackson2HttpMessageConverter());
requestMappingHandlerAdapter.setMessageConverters(messageConverters);
return requestMappingHandlerAdapter;
}
//@Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(){
MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter =new MappingJackson2HttpMessageConverter();
List<MediaType> supportedMediaTypes =new ArrayList<>();
supportedMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
mappingJackson2HttpMessageConverter.setSupportedMediaTypes(supportedMediaTypes);
return mappingJackson2HttpMessageConverter;
}
@Bean
public RestTemplate restTemplate(){
RestTemplate restTemplate =new RestTemplate();
return restTemplate;
}
}
5.3 Controller
主要包含UserController
UserController.java
package com.ekeyfund.springcloud.controller;
import com.ekeyfund.springcloud.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* UserController
*
* @author tony [email protected]
* @create 2017-06-27-下午11:42
* @see
* @since JDK1.8u133
*/
@RestController
public class UserController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("user/get/{id}")
public User get(@PathVariable Long id){
return this.restTemplate.getForObject("http://127.0.0.1:9996/get/{1}",User.class,id);
}
}
5.4 應用配置
主要包含springboot的application.properties
application.properties
server.port=9991
server.tomcat.uri-encoding=UTF-8
5.5 啟動類
package com.ekeyfund.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringcloudConsumerH5Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudConsumerH5Application.class, args);
}
}
5.6 測試服務呼叫
9991埠的服務消費者會呼叫9996埠的服務提供者介面。
通常在實際的開發中會遇到類似的情景:例如PC/H5/Android/IOS會去呼叫User模組的登入服務。
弊端:因為程式呼叫的IP和埠採用了硬編碼,而IP和埠可能變更,因此難以維護。
而當服務提供者宕機後服務會不可用,後面會在系統中引入服務註冊、發現元件,該元件主要是維護了一個服務登錄檔,服務提供者和消費者將服務註冊到該登錄檔中,而服務註冊和發現元件會通過傳送心跳來判斷服務是否可用。
六 使用Eureka實現服務發現元件
所屬maven模組:springcloud-eureka-server
1 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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ekeyfund.springcloud</groupId>
<artifactId>springcloud-eureka-server</artifactId>
<packaging>jar</packaging>
<name>springcloud-eureka-server</name>
<description>SpringCloud Eureka Server </description>
<parent>
<groupId>com.ekeyfund.springcloud</groupId>
<artifactId>springcloud-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<properties>
<start-class>com.ekeyfund.springcloud.SpringcloudEurekaServerApplication&l