欢迎访问 生活随笔!

生活随笔

当前位置: 首页 >

springboot教程(三)

发布时间:2024/9/16 42 豆豆
生活随笔 收集整理的这篇文章主要介绍了 springboot教程(三) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

撸了今年阿里、头条和美团的面试,我有一个重要发现.......>>>

springboot微服务

新建项目mallproduct

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.edu.mall.product</groupId><artifactId>mall-product</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.1.4.RELEASE</version><scope>import</scope><type>pom</type></dependency></dependencies></dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>LATEST</version></dependency></dependencies></project>

在resources下新建product.sql,内容如下:

CREATE database db_products default charset utf8; create table products (pid int not null primary key auto_increment, pname varchar (200), type varchar (50), price double, createTime timestamp )

在mysql中执行上面的sql语句。

然后在resources下新建application.properties,内容如下:

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://192.168.152.45:3306/db_products?useSSL=false&characterEncoding=utf8 spring.datasource.username=root spring.datasource.password=123456spring.jackson.date-format=yyyy-MM-dd HH:mm:ss

spring.jackson.date-format=yyyy-MM-dd HH:mm:ss 可以将返回的时间格式化,否则会返回类似2019-06-04T22:06:56.000+0000的时间格式

spring.jackson.time-zone=GMT-5 数据库的时间与springboot返回的时间不一致,需要修改时区

新建包com.edu.mall.product,新建bean包,并且建立product.java,内容如下:

package com.edu.mall.product.bean;import java.sql.Timestamp;public class Product {private Integer pid;private String pname;private String type;private Double price;private Timestamp createTime;@Overridepublic String toString() {return "Product{" +"pid=" + pid +", pname='" + pname + '\'' +", type='" + type + '\'' +", price=" + price +", createTime=" + createTime +'}';}public Integer getPid() {return pid;}public void setPid(Integer pid) {this.pid = pid;}public String getPname() {return pname;}public void setPname(String pname) {this.pname = pname;}public String getType() {return type;}public void setType(String type) {this.type = type;}public Double getPrice() {return price;}public void setPrice(Double price) {this.price = price;}public Timestamp getCreateTime() {return createTime;}public void setCreateTime(Timestamp createTime) {this.createTime = createTime;} }

新建mapper包,在mapper包中,新建ProductMapper.java,内容如下:

package com.edu.mall.product.mapper;import com.edu.mall.product.bean.Product; import org.apache.ibatis.annotations.*;import java.util.List;@Mapper public interface ProductMapper {@Insert("insert into products (pname,type,price) values (#{pname}, #{type}, #{price})")public Integer add(Product product);@Delete("delete from products where pid=#{arg1}")public Integer deleteById(Integer pid);@Update("update products set pname=#{pname}, type=#{type}, price=#{price} where pid=#{pid}")public Integer update(Product product);@Select("select * from products where pid=#{arg1}")public Product getById(Integer pid);@Select("select * from products order by pid desc")public List<Product> queryByList(); }

测试mybatis是否配置成功,App.java中的内容如下:
 

package com.edu.mall.product;import com.edu.mall.product.bean.Product; import com.edu.mall.product.mapper.ProductMapper; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext;@SpringBootApplication public class App {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(App.class, args);ProductMapper productMapper = run.getBean(ProductMapper.class);Product product = new Product();product.setPname("java入门到精通");product.setPrice(10.0);product.setType("计算机");productMapper.add(product);run.close();}}

点击运行App.java 可以成功插入到mysql数据库中。说明mybatis已经集成成功了。

将上面的App.java中的测试关闭。

新建web包,然后新建Respose.java 内容如下:

package com.edu.mall.product.web;public class Response {/*** 200 表示成功* 500 表示失败*/private String code;private String msg;private Object data;@Overridepublic String toString() {return "Response{" +"code='" + code + '\'' +", msg='" + msg + '\'' +", data=" + data +'}';}public Response(String code, String msg) {this.code = code;this.msg = msg;}public Response(String code, String msg, Object data) {this.code = code;this.msg = msg;this.data = data;}public String getCode() {return code;}public void setCode(String code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Object getData() {return data;}public void setData(Object data) {this.data = data;} }

新建controller包,然后新建ProductController.java,内容如下

package com.edu.mall.product.controller;import com.edu.mall.product.bean.Product; import com.edu.mall.product.mapper.ProductMapper; import com.edu.mall.product.web.Response; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*;import java.util.List;/*** product rest 服务*/ @RestController public class ProductController {@Autowiredprivate ProductMapper productMapper;@PostMapping("/soa/product/add")public Object add(Product product) {Integer res = productMapper.add(product);return res == 1 ? new Response("200", "OK") : new Response("500", "Fail");}@PutMapping("/soa/product/update")public Object update(Product product) {Integer res = productMapper.update(product);return res == 1 ? new Response("200", "OK") : new Response("500", "Fail");}@PostMapping("/soa/product/{id}")public Object get(@PathVariable("id") Integer id) {Product product = productMapper.getById(id);return new Response("200", "OK", product);}@DeleteMapping("/soa/product/{id}")public Object delete(@PathVariable("id") Integer id) {Integer res = productMapper.deleteById(id);return res == 1 ? new Response("200", "OK") : new Response("500", "Fail");}@GetMapping("/soa/products")public Object list(Integer id) {List<Product> products = productMapper.queryByList();return new Response("200", "OK", products);}}

运行App.java,使用postman测试运行成功。

新建项目mallweb

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.edu.mall.product</groupId><artifactId>mall-web</artifactId><version>1.0-SNAPSHOT</version><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target></properties><dependencies><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.1.6.RELEASE</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-web</artifactId><version>5.1.6.RELEASE</version></dependency></dependencies></project>

同时将mallproduct中的Product.java和Response.java拷贝到这个项目中,新建App.java

package com.edu.mall.web;import com.google.gson.Gson; import org.springframework.web.client.RestTemplate; import web.Response;public class App {static String BASE_URL = "http://127.0.0.1:8080";public static void main(String[] args) {RestTemplate restTemplate = new RestTemplate();String body = restTemplate.getForObject(BASE_URL + "/soa/product/1", String.class);System.out.println(body);Response response = new Gson().fromJson(body, Response.class);System.out.println(response);System.out.println(response.getCode());System.out.println(response.getMsg());System.out.println(response.getData());} }

把原先的一个大系统,拆分成小的系统

    每个小系统分别开发,测试,维护。

调用方式:

    服务提供的是什么服务?rest(http),web service,rpc

        rest方式可以使用RestTemplate, httpclient

 springboot 服务注册与发现

web端调用服务的方式常用的有两种:

    1. Nginx,将服务地址配置在Nginx,由web端连接Nginx做代理,Nginx做负载均衡,但是这种方式是静态方式,每部署一台就需要在Nginx配置上。

    2. 注册中心,服务方(微服务),调用方。首先服务提供方将服务提供到注册中心,然后调用方从注册中心拿到地址,通常服务提供方把自己的地址(ip:port)提交到注册中心,调用方从注册中心获取ip和端口号,获取之后,就可以直接与服务方连接调用。好处就是服务是可以动态添加和删除。如果获取到多个ip和端口,可以使用负载均衡算法选择其中的一个。还有一个好处就是,调用方只需要知道注册中心的地址,不需要服务端的地址。只需要维护一个ip地址就可以了。

如何实现注册中心?

本节依然使用上面的项目mallproduct和mallweb

zookeeper,consul,etcd,redis,通常使用这几种来作为注册中心。

使用zookeeper来作为注册中心。使用curator框架使用zookeeper,curator对zookeeper进行了封装。

首先加载curator依赖:

    服务注册方添加依赖:在mall-Product/pom.xml中:

    

<dependency><groupId>org.apache.curator</groupId><artifactId>curator-x-discovery-server</artifactId><version>4.2.0</version></dependency>

    服务发现方添加依赖:在mall-web/pom.xml中

<dependency><groupId>org.apache.curator</groupId><artifactId>curator-x-discovery</artifactId><version>4.2.0</version></dependency>

服务的注册 

常见的注册中心:zookeeper, consul, etcd, redis
服务提供方,需要在服务启动的时候,把服务的信息(ip,端口)注册到注册中心(zookeeper)

在mall-product中新建ServiceRegister.java

package com.edu.mall.product;import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.RetryOneTime; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component;@Component public class ServiceRegister implements ApplicationRunner {@Value("${zookeeper.address}")private String zkAddress;@Overridepublic void run(ApplicationArguments args) throws Exception {CuratorFramework client = CuratorFrameworkFactory.newClient(zkAddress, new RetryOneTime(1000));client.start();client.blockUntilConnected();ServiceInstance<Object> instance = ServiceInstance.builder().name("product").address("192.168.170.132").port(8080).build();ServiceDiscovery<Object> serviceDiscovery = ServiceDiscoveryBuilder.builder(Object.class).client(client).basePath("/soa").build();serviceDiscovery.registerService(instance);serviceDiscovery.start();System.out.println("service register success");} }

在application.properties中添加配置:

zookeeper.address=192.168.152.45:2181

运行App.java,控制台显示service register success,说明服务注册成功。

查看zookeeper,使用命令

iie4bu@hostdocker:~/apache-zookeeper-3.5.5-bin/bin$ ./zkCli.sh [zk: localhost:2181(CONNECTED) 0] ls / [soa, zookeeper] [zk: localhost:2181(CONNECTED) 1]

可以看到有了soa节点,查看soa下面的服务:

[zk: localhost:2181(CONNECTED) 2] ls /soa [product] [zk: localhost:2181(CONNECTED) 3

可以看到product服务的名字。继续查看:

[zk: localhost:2181(CONNECTED) 3] ls /soa/product [f63b4b19-e313-419a-acba-5aab6e08fc25] [zk: localhost:2181(CONNECTED) 4]

查看详细信息:

[zk: localhost:2181(CONNECTED) 4] get /soa/product/f63b4b19-e313-419a-acba-5aab6e08fc25 {"name":"product","id":"f63b4b19-e313-419a-acba-5aab6e08fc25","address":"192.168.170.132","port":8080,"sslPort":null,"payload":null,"registrationTimeUTC":1560151924584,"serviceType":"DYNAMIC","uriSpec":null} [zk: localhost:2181(CONNECTED) 5]

服务的发现

在项目mallweb中新建Client.java

package com.edu.mall.web;import com.google.gson.Gson; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.RetryOneTime; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.springframework.web.client.RestTemplate; import web.Response;import java.util.Collection;public class Client {public static void main(String[] args) throws Exception {CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.152.45:2181", new RetryOneTime(1000));client.start();client.blockUntilConnected();RestTemplate restTemplate = new RestTemplate();ServiceDiscovery<Object> serviceDiscovery = ServiceDiscoveryBuilder.builder(Object.class).client(client).basePath("/soa").build();Collection<ServiceInstance<Object>> products = serviceDiscovery.queryForInstances("product");products.forEach((instance) -> {System.out.println(instance.getAddress());System.out.println(instance.getPort());});} }

输出如下:

192.168.170.132 8080

说明可以发现服务。

调用服务,修改Client.java

package com.edu.mall.web;import com.google.gson.Gson; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.RetryOneTime; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.springframework.web.client.RestTemplate; import web.Response;import java.util.Collection;public class Client {public static void main(String[] args) throws Exception {CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.152.45:2181", new RetryOneTime(1000));client.start();client.blockUntilConnected();ServiceDiscovery<Object> serviceDiscovery = ServiceDiscoveryBuilder.builder(Object.class).client(client).basePath("/soa").build();Collection<ServiceInstance<Object>> products = serviceDiscovery.queryForInstances("product");products.forEach((instance) -> {RestTemplate restTemplate = new RestTemplate();String body = restTemplate.getForObject("http://" + instance.getAddress() + ":" + instance.getPort() +"/soa/product/1", String.class);System.out.println(body);Response response = new Gson().fromJson(body, Response.class);});} }

输出结果如下:

{"code":"200","msg":"OK","data":{"pid":1,"pname":"python入门","type":"计算机类","price":133.0,"createTime":"2019-06-04 17:06:56"}}

说明调用成功。

这种情况下,每调用一次就往注册中心查一次,一般在正式的环境中不这样做,一般会从缓存中拿取。

服务发现
 在进行服务调用的时候,需要先从注册中心获取到服务的地址,然后根据获取到的服务地址进行调用

 目前我们只获取到一个服务,如果我们要获取到多个服务如何做?

将mall-product复制一份,改名为mall-product2

修改mall-product2的端口号为9090。同时在ServiceRegister.java中修改端口号为9090:

ServiceInstance<Object> instance = ServiceInstance.builder().name("product").address("192.168.170.132").port(9090).build();

运行mall-product和mall-product2,然后可以看到有两个服务启动:

[zk: localhost:2181(CONNECTED) 22] ls /soa/product [19568e15-9a90-4174-953f-f00124bc9595, 59eae9c2-525c-455e-839a-d3a2284bcf19]

然后运行mall-web项目的Client.java,输出结果如下:

{"code":"200","msg":"OK","data":{"pid":1,"pname":"python入门","type":"计算机类","price":133.0,"createTime":"2019-06-04 17:06:56"}} {"code":"200","msg":"OK","data":{"pid":1,"pname":"python入门","type":"计算机类","price":133.0,"createTime":"2019-06-04 17:06:56"}}

输出了两遍,我们需要根据算法做一些选择。随机或者轮训。新建LoadBalance.java

package com.edu.mall.web;import java.util.List;public class LoadBalance {private List<String> services;private int index = 0;public LoadBalance(List<String> services) {this.services = services;}public String choose() {String service = services.get(index);index++;if (index >= services.size()) {index = 0;}return service;} }

然后修改Client.java

package com.edu.mall.web;import com.google.gson.Gson; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.retry.RetryOneTime; import org.apache.curator.x.discovery.ServiceDiscovery; import org.apache.curator.x.discovery.ServiceDiscoveryBuilder; import org.apache.curator.x.discovery.ServiceInstance; import org.springframework.web.client.RestTemplate; import web.Response;import java.util.ArrayList; import java.util.Collection; import java.util.List;/*** 服务发现* 在进行服务调用的时候,需要先从注册中心获取到服务的地址,然后根据获取到的服务地址进行调用*/ public class Client {public static void main(String[] args) throws Exception {CuratorFramework client = CuratorFrameworkFactory.newClient("192.168.152.45:2181", new RetryOneTime(1000));client.start();client.blockUntilConnected();ServiceDiscovery<Object> serviceDiscovery = ServiceDiscoveryBuilder.builder(Object.class).client(client).basePath("/soa").build();Collection<ServiceInstance<Object>> products = serviceDiscovery.queryForInstances("product");final List<String> services = new ArrayList<>();products.forEach((instance) -> {services.add(instance.getAddress() + ":" + instance.getPort());});LoadBalance loadBalance = new LoadBalance(services);RestTemplate restTemplate = new RestTemplate();String body = restTemplate.getForObject("http://" + loadBalance.choose() + "/soa/product/1", String.class);System.out.println(body);Response response = new Gson().fromJson(body, Response.class);} }

这样当多个服务端提供服务时,可以轮训进行服务提供,当某个服务down掉后不影响。

springboot打包运行

方法一

在项目路径下执行:

mvn clean package

可以将项目打包成jar包,但是依赖没有加进去。

使用命令

mvn clean package dependency:copy-dependencies

可以将依赖包拷贝到target/dependency路径下,然后将mall-product-1.0-SNAPSHOT.jar也拷贝到target/dependency下,在target路径下执行:

java -Djava.ext.dirs=dependency com.edu.mall.product.App

执行成功

方法二

总结

以上是生活随笔为你收集整理的springboot教程(三)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。