1. 程式人生 > >SpringBoot +SpringCloud微服務示例,整合FreeMaker,AngularJS

SpringBoot +SpringCloud微服務示例,整合FreeMaker,AngularJS

乾貨一篇,本節以SpringBoot + SpringCloud為例 構建輕量級微服務,旨在推薦一種更加敏捷的開發流程,本篇暫不會提及相關概念,皆以程式碼示意.
GIT:https://github.com/poai/spring-cloud-zookeeper-demo.git
關鍵技術簡介:
  • Zookeeeper,分散式協同服務,叢集環境中使用的較多,微服務中用來做服務發現,負載均衡,Leader選舉等.
  • SpringBoot,敏捷開發框架,集Spring,SpirngMVC等Spring體系內技術於一體,基於IOC容器進行資源整合,遮蔽了開發,部署應用程式的複雜性.
  • SpringCloud,雲環境的產物,致力於解決分散式解決方案整合,與SpringCloud無縫整合.
Server端實現:
  • POM依賴
<dependencies>
		<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zookeeper-discovery -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
			<version>1.0.2.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-feign -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-feign</artifactId>
		</dependency>
	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-netflix</artifactId>
				<version>1.2.5.RELEASE</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>
  • SpringBoot 核心配置檔案 application.yml
server:
  port: 9997
spring:
  application:
    #服務名稱,CLIENT端用來享受服務
    name: USERSERVER
  cloud:
    zookeeper:
      #ZK_ADDRESS
      connect-string: host219:2181,host223:2181,host224:2181
      discovery:
        register: true
        #服務地址
        instance-host: 10.150.27.29
        #服務埠
        instance-port: ${server.port}
        enabled: true
    

  • server端應用程式入口函式ZkServerApplication.java
@SpringBootApplication
@RestController
//服務註冊到ZK
@EnableDiscoveryClient
public class ZkServerApplication {
	public static void main(String[] args) {
		SpringApplication.run(ZkServerApplication.class, args);
	}
}
  • server端 RESTFULL 介面示例
public class Bean {
	private String name;
	private String likes;
	private String id;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getLikes() {
		return likes;
	}

	public void setLikes(String likes) {
		this.likes = likes;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

}
@RestController
public class UserService {
	// PathVariable
	@RequestMapping("/user/{id}")
	public Bean getUserInfo(@PathVariable("id") String id) {
		Bean bean = new Bean();
		bean.setLikes("Orange");
		bean.setName("lili");
		bean.setId(id);
		return bean;
	}
	// Path
	@RequestMapping
	public Bean getUserList(@RequestParam(required = true, value = "id") String id) {
		Bean bean = new Bean();
		bean.setLikes("Banana");
		bean.setName("Mr Wang");
		bean.setId(id);
		return bean;
	}
}

Server端總結:每啟動一個Server端例項SpringCloud向ZK以"USERSERVER"為服務唯一標識在ZK "/services"節點下以該服務標識為路徑註冊服務,該特性由"@EnableDiscoveryClient" 註解及application.yml中相關配置進行驅動.

Client端實現

  • POM依賴
<dependencies>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter</artifactId>
	</dependency>
	<!-- FEGIN:REST CLIENT -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-feign</artifactId>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-ribbon -->
	<!-- RIBBON:客戶端負載均衡器 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-ribbon</artifactId>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-hystrix -->
	<!-- HYSTRIX:斷路器 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-hystrix</artifactId>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zookeeper-discovery -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
		<version>1.0.2.RELEASE</version>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-freemarker -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-freemarker</artifactId>
	</dependency>
	<!-- 熱部署包 -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-devtools</artifactId>
		<optional>true</optional>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
	<dependency>
		<groupId>org.springframework</groupId>
		<artifactId>spring-jdbc</artifactId>
	</dependency>
	<!-- https://mvnrepository.com/artifact/oracle/ojdbc14 -->
	<!-- https://mvnrepository.com/artifact/oracle/ojdbc14 -->
	<dependency>
		<groupId>oracle</groupId>
		<artifactId>ojdbc14</artifactId>
		<version>10.2.0.1.0</version>
	</dependency>

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-configuration-processor</artifactId>
		<optional>true</optional>
	</dependency>
	<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-jdbc</artifactId>
	</dependency>

</dependencies>


  • SpringBoot 核心配置檔案 application.yml
server:
  port: 9990
spring:
  application:
    name: USERCLIENT
  cloud:
    zookeeper:
      enabled: true
      connect-string: host219:2181,host223:2181,host224:2181
      discovery:
        root: /services
        register: true
  datasource:
    url: jdbc:oracle:thin:@host233:1521/orcl
    username: root
    password: root
    driver-class-name : oracle.jdbc.driver.OracleDriver


  • client端主函式實現,ZkClientApplication.java
@SpringBootApplication
// 啟用REST 客戶端
@EnableFeignClients
// 啟用客戶端負載均衡
@RibbonClient(name = "my", configuration = RibbonConfig.class)
// 啟用服務發現
@EnableDiscoveryClient
// 啟用斷路器
@EnableHystrix
@ImportResource(value = "spring_mvc.xml")
@ComponentScan("cn.com.xiaofen")
public class ZkClientApplication {
	public static void main(String[] args) {
		SpringApplication.run(ZkClientApplication.class, args);
	}
	/* Spring JDBC */
	@Bean
	public JdbcTemplate primaryJdbcTemplate(DataSource dataSource) {
		return new JdbcTemplate(dataSource);
	}

	/* TOMCAT DataSourcePool */
	@Bean
	@ConfigurationProperties(prefix = "spring.datasource")
	public DataSource dataSource() {
		return DataSourceBuilder.create().build();
	}
}
  • client消費指定server控制器即service實現,主函式中使用@EnableDiscoveryClient註解驅動服務自動發現,使用@RibbonClient註解驅動客戶端負載均衡器,使用@EnableFeignClients註解驅動以REST CLIENT註解形式進行RPC呼叫,@FeignClient 指向一個經過客戶端負載均衡後選擇的Service連線並消費服務,服務介面的例項化由Spring框架實現並完成自動裝配.
@RestController
public class UserController {

	@Autowired
	private UserService us;

	@RequestMapping("/user/{id}")
	public String getUserInfo(@PathVariable("id") String id) {
		return us.getUserInfo(id);
	}
	@RequestMapping("/user")
	public String getUSerList(@RequestParam("id") String id) {
		return us.getUSerList(id);
	}
}
@FeignClient("USERSERVER")
public interface UserService {
	@RequestMapping("/user/{id}")
	public String getUserInfo(@PathVariable("id") String id);
	@RequestMapping("/user")
	public String getUSerList(@RequestParam("id") String id);
}

  • 配置資料來源,推薦使用Tomcat內建資料來源,配置屬性見application.yml ,資料來源建立並注入IOC過程見ZkClientApplication.java 主函式,有註釋,DAO層可以使用JdbcTemplate 獲取其它開源框架如Mybatis,Hibernate等.
  • 與FreeMaker整合,SpringBoot中不推薦使用JSP,JSP帶來的劣勢在於專案不能以獨立jar的形式釋出,這裡一FreeMaker為例,只需要新增SpringBoot FreeMaker的依賴即可. 見POM依賴.
Controller
@Controller
public class ByonetController {
	@Autowired
	private JdbcTemplate jdbcTemplate;
	@RequestMapping("/byonetListFreeMaker")
	public String byonetListFreeMaker(Map<String,Object> model) {
		String sql = "select kkid,kkmc,x,y from t_itgs_tgsinfo";
		BeanPropertyRowMapper<Byonet> rowMapper = new BeanPropertyRowMapper<Byonet>(Byonet.class);
		List<Byonet> byonets=jdbcTemplate.query(sql, rowMapper);
		model.put("byonets", byonets);
		return "byonetList";
	}
}

FreeMaker模版,路徑src/main/resources/remplates/byonetList.ftl
<html>
<head>
  <title>卡點列表</title>
</head>
<body>
  <p>Our latest product:
  
  <table>
  	<tr>
  		<th>KKID</th>
  		<th>KKMC</th>
  		<th>X</th>
  		<th>Y</th>
  	</tr>
  	<#list byonets as byonet>
  		<tr>
  			<td>${byonet.kkid}</td>
  			<td>${byonet.kkmc}</td>
  			<td>${ (byonet.x)! }</td>
  			<td>${ (byonet.y)!}</td>
  		</tr>
  	</#list>
  </table>
</body>
</html>
  • AngularJS嚐鮮,

controller

@RestController
public class ByonetControllerRest {
	@Autowired
	private JdbcTemplate jdbcTemplate;

	@RequestMapping("/byonetList")
	public List<Byonet> byonetList() {
		String sql = "select kkid,kkmc,x,y from t_itgs_tgsinfo";
		BeanPropertyRowMapper<Byonet> rowMapper = new BeanPropertyRowMapper<Byonet>(Byonet.class);
		return jdbcTemplate.query(sql, rowMapper);
	}
	
	@RequestMapping("/byonetList/{kkid}")
	public List<Byonet> byonetListById(@PathVariable(required=true,name="kkid")String kkid) {
		String sql = "select kkid,kkmc,x,y from t_itgs_tgsinfo where kkid=?";
		BeanPropertyRowMapper<Byonet> rowMapper = new BeanPropertyRowMapper<Byonet>(Byonet.class);
		return jdbcTemplate.query(sql, rowMapper,kkid);
	}
}

index.html ,下例以請求REST SERVER獲取JSON集合填充一個表格為例,此外推薦學習VUE.JS
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script
	src="http://cdn.static.runoob.com/libs/angular.js/1.4.6/angular.min.js"></script>
<script src="js/index.js"></script>
</head>
<body>
	<h1>RPC測試</h1>
	<a href="http://it:9990/byonetListFreeMaker" id="info">info_1</a>
	<br>
	<a href="http://it:9990/homePage" id="list">info_2</a>
	<br>
	<h1>FreeMaker測試</h1>
	<a href="http://it:9990/byonetListFreeMaker" id="info">/byonetListFreeMaker</a>
	<br>
	<a href="http://it:9990/homePage" id="list">/homePage</a>
	<hr>
	<hr>
	<h1>AngularJS 測試</h1>
	<div ng-app="myApp" ng-controller="customersCtrl">
		<table>
			<tr>
				<td>ID</td>
				<td>NAME</td>
				<td>X</td>
				<td>Y</td>
				<td>HAND</td>
			</tr>
			<tr ng-repeat="x in names">
				<td><a href="">{{ x.kkid }}</a></td>
				<td>{{ x.kkmc }}</td>
				<td>{{ x.x }}</td>
				<td>{{ x.y }}</td>
				<td><a href="">info</a></td>
			</tr>
		</table>
		<script>
			var app = angular.module('myApp', []);
			app.controller('customersCtrl', function($scope, $http) {
				$http.get("/byonetList").success(function(response) {
					$scope.names = response;
				});
			});
		</script>
</body>
</html>