java.ws.rs 是 jax-rs 规范中定义的包名。
jax-rs
全程 Java API for RESTful Services
关于jax-rs相关的
参考:
https://blog.csdn.net/wabiaozia/article/details/70487306
https://www.cnblogs.com/caogen1991/p/7902722.html
https://blog.csdn.net/skdhfdfc/article/details/83823479
通过maven新建两个聚合父工程及其三个子模块工程
聚合工程的创建参考:https://blog.csdn.net/weixin_42465125/article/details/87906095
product-center和user-center分别最为两个父工程,聚合product-center-*和user-center-*这些子模块
子模块之间有依赖关系,比如:product-center-service依赖product-center-api,而product-center-api依赖product-center-model
同时结合Maven的依赖传递,product-center-service会同时依赖product-center-api和product-center-model,具体配置参考相应的pom文件
例子学习目标:
1:学习使用javax.ws.rs构建Restful API
2:借助Dubbo实现product-center-service远程调用user-center-service
下面一个一个工程模块简单介绍和代码示例:
user-center父工程:
pom文件:其实没得什么内容,就是聚合的模块,这些都是在建立子模块的时候自动生成的
<?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>cn.cuit.user</groupId>
<artifactId>user-center</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>user-center-model</module>
<module>user-center-api</module>
<module>user-center-service</module>
</modules>
</project>
user-center-model子模块
pom文件:依赖
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.cuit.user</groupId>
<artifactId>user-center</artifactId>
<version>1.0</version>
</parent>
<artifactId>user-center-model</artifactId>
<name>user-center-model</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
</dependencies>
</project>
Model类:
package cn.cuit.user.center.model;
import java.io.Serializable;
public class User implements Serializable {
private static final long serialVersionUID = 1L;
private String username;
private String password;
public User() {
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
user-center-api子模块:
pom文件:
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.cuit.user</groupId>
<artifactId>user-center</artifactId>
<version>1.0</version>
</parent>
<artifactId>user-center-api</artifactId>
<name>user-center-api</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.cuit.user</groupId>
<artifactId>user-center-model</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
api模块依赖model模块,pom添加完后 需要执行maven install 将他们分别打成jar到本地仓库,才能被依赖,后面如果有依赖都是相同的处理,后面就不在赘述【其实这种多模块的有很多坑的,比如clean后一定要在执行install,有时就可能遗忘,更新pom依赖后有时需要update,问题挺多的,嗯.... 慢慢搞吧】
Service接口
package cn.cuit.user.center.api;
import cn.cuit.user.center.model.User;
public interface UserService {
User getUserByUsername(String username);
String testCallUserService();
}
user-center-service子模块:
pom文件:
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.cuit.user</groupId>
<artifactId>user-center</artifactId>
<version>1.0</version>
</parent>
<artifactId>user-center-service</artifactId>
<name>user-center-service</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.cuit.user</groupId>
<artifactId>user-center-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>cn.cuit.product</groupId>
<artifactId>product-center-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>2.0.1.Final</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>1.3.0-GA</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.3.0-GA</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
properties配置文件:
# 启用aop自动代理,默认就是true
spring.aop.auto = true
# 使用cglib的动态代理,默认true
spring.aop.proxy-target-class = true
# 服务访问端口
server.port = 8088
# 服务应用名称
spring.application.name=user-center-provider
# logback日志配置,日志环境类型,服务名,级别
log.env.profile = dev
log.env.module = user-center-provider
log.env.logger.level = info
#服务上下文配置,springboot2.x后写法
server.servlet.context-path = /user
# Service版本
user.service.version = 1.0
# Dubbo Components 扫描 (@Service【Dubbo提供的,不是Spring的】 , @Reference)
dubbo.scan.basePackages = cn.cuit.user.center.service
# Dubbo Config properties
dubbo.application.id = user-center-provider
dubbo.application.name = user-center-provider
dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 20880
dubbo.provider.timeout = 5000
dubbo.registry.id = my-registry
dubbo.registry.address = zookeeper://127.0.0.1:2181
#Zookeeper集群的配置方式
#dubbo.registry.address = zookeeper://192.168.174.226:2181?backup=192.168.174.227:2181,192.168.174.228:2181
Zookeeper集群的搭建方式参考:https://blog.csdn.net/weixin_42465125/article/details/87519124
日志配置文集:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<property resource="application.properties"/>
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/${log.env.module}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/${log.env.module}-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxFileSize>5MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} - %msg%n</Pattern>
</layout>
</appender>
<root level="${log.env.logger.level}">
<appender-ref ref="ROLLING"/>
</root>
</configuration>
Boot启动类:
package cn.cuit.user.center;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Controller类:
package cn.cuit.user.center.controller;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import cn.cuit.user.center.api.UserService;
import cn.cuit.user.center.model.User;
@Service
@Path("/api/users")
@Consumes({ MediaType.APPLICATION_JSON_UTF8_VALUE })
@Produces({ MediaType.APPLICATION_JSON_UTF8_VALUE })
public class UserController {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
@Autowired
private UserService userService;
// @GetMapping(value = "/getUserByUsername/{username}")
@GET
@Path("/getUserByUsername/{username}")
// 这里的路径参数使用Spring的@PathVariable获取不到,要使用下面这个注解
public User getUserByUsername(@PathParam(value = "username") String username) {
LOG.info("username = {}", username);
return userService.getUserByUsername(username);
}
@GET
@Path("/testCallUserService")
public String testCallUserService() {
return userService.testCallUserService();
}
}
Service实现:
package cn.cuit.user.center.service;
import org.springframework.stereotype.Component;
import com.alibaba.dubbo.config.annotation.Service;
import cn.cuit.user.center.api.UserService;
import cn.cuit.user.center.model.User;
@Service(version = "${user.service.version}", validation = "true", timeout = 5000)
@Component("userService")
public class UserServiceImpl implements UserService {
@Override
public User getUserByUsername(String username) {
User user = new User();
user.setUsername("userService : CUIT ->" + username);
user.setPassword("userService : rootllb");
return user;
}
@Override
public String testCallUserService() {
return "user-center-service -> testCallUserService has been called";
}
}
测试user-center服务
首先启动Zookeeper,看看服务注册是否好使
Zookeeper快速安装参考:https://blog.csdn.net/weixin_42465125/article/details/88011991
通过IDEA查看可以看到UserService注册成功了的,或者使用命令行zkCli连接查看
启动入口类访问:
http://localhost:8088/user/api/users/getUserByUsername/dsadsa
目前来说UserService单独自身是可以访问的了
下面来实验product-center,实现远程调用UserService
product-center父工程:
pom文件:
<?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>cn.cuit.product</groupId>
<artifactId>product-center</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>product-center-model</module>
<module>product-center-api</module>
<module>product-center-service</module>
</modules>
</project>
product-center-model子模块:
pom文件:
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.cuit.product</groupId>
<artifactId>product-center</artifactId>
<version>1.0</version>
</parent>
<artifactId>product-center-model</artifactId>
<name>product-center-model</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
</dependencies>
</project>
Product类:
package cn.cuit.product.center.model;
import java.io.Serializable;
public class Product implements Serializable {
private static final long serialVersionUID = 2547456019658847542L;
private String name;
private Integer price;
public Product() {
}
public Product(String name, Integer price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
}
product-center-api子模块:
pom文件:
<?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>cn.cuit.product</groupId>
<artifactId>product-center</artifactId>
<version>1.0</version>
<packaging>pom</packaging>
<modules>
<module>product-center-model</module>
<module>product-center-api</module>
<module>product-center-service</module>
</modules>
</project>
Service接口:
package cn.cuit.product.center.api;
import cn.cuit.product.center.model.Product;
public interface ProductService {
Product getProductById(String id);
}
product-center-service子模块:
pom文件:
<?xml version="1.0"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.cuit.product</groupId>
<artifactId>product-center</artifactId>
<version>1.0</version>
</parent>
<artifactId>product-center-service</artifactId>
<name>product-center-service</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>cn.cuit.product</groupId>
<artifactId>product-center-api</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>cn.cuit.user</groupId>
<artifactId>user-center-service</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-spring-boot-starter</artifactId>
<version>2.0.1.Final</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-dubbo-adapter</artifactId>
<version>1.3.0-GA</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-annotation-aspectj</artifactId>
<version>1.3.0-GA</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.56</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.1.0.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
注意事项:这里要去调用UserService接口,所以要依赖user-center-service模块,但是请注意两个工程之间不能循环依赖,即现在product-center-service依赖了user-center-service,此时user-center-service就不能去依赖product-center-service,否则编译出错
properties配置文件:
spring.aop.auto = true
spring.aop.proxy-target-class = true
server.port = 8081
spring.application.name = product-center-provider
log.env.profile = dev
log.env.module = product-center-provider
log.env.logger.level = info
server.servlet.context-path = /product
product.service.version = 1.0
dubbo.scan.basePackages = cn.cuit.product.center.service
# Dubbo Config properties
dubbo.application.id = product-center-provider
dubbo.application.name = product-center-provider
dubbo.protocol.id = dubbo
dubbo.protocol.name = dubbo
dubbo.protocol.port = 20881
dubbo.provider.timeout = 5000
dubbo.registry.id = my-registry
dubbo.registry.address = zookeeper://127.0.0.1:2181
#Zookeeper集群的配置方式
#dubbo.registry.address = zookeeper://192.168.174.226:2181?backup=192.168.174.227:2181,192.168.174.228:2181
Zookeeper集群的搭建方式参考:https://blog.csdn.net/weixin_42465125/article/details/87519124
日志配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<property resource="application.properties"/>
<appender name="ROLLING" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/${log.env.module}.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<fileNamePattern>logs/${log.env.module}-%d{yyyy-MM-dd}.%i.log
</fileNamePattern>
<maxFileSize>5MB</maxFileSize>
<maxHistory>30</maxHistory>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<layout class="ch.qos.logback.classic.PatternLayout">
<Pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{35} - %msg%n</Pattern>
</layout>
</appender>
<root level="${log.env.logger.level}">
<appender-ref ref="ROLLING"/>
</root>
</configuration>
Boot启动类:
package cn.cuit.product.center;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
Controller类:
package cn.cuit.product.center.controller;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.dubbo.config.annotation.Reference;
import cn.cuit.product.center.api.ProductService;
import cn.cuit.product.center.model.Product;
import cn.cuit.user.center.api.UserService;
import cn.cuit.user.center.model.User;
/**
* 总结:
*
* 使用javax.ws.rs包实现RestFul的类,他和Spring的不能混用,只能用它提供的
*
* @RestController @RequestMapping @PathVariable这些Spring的注解等貌似不好使
* 在方法上使用@RequestMapping映射请求的url访问不了【类上面的Spring注解 @Service, @Controller, @RestController, @Component都是可以的
* 他们都是语义区别上的@Component,可以看他们的源码都是被@Component注解修饰的】
*
* maven clean后一定要执行maven install, 否则启动说找不到启动类
*
* 由于使用了Jrebel热部署,但是如果修改了代码发现不好使了,重启试试
*
* 两个service之间不能相互依赖,会报错,可以看下面的Problems视图有提示
*
* 可以结合IDEA 的zookeeper视图查看注册的服务
*
*/
// @Service
@RestController
@Path("/api/products")
@Consumes({ MediaType.APPLICATION_JSON_UTF8_VALUE })
@Produces({ MediaType.APPLICATION_JSON_UTF8_VALUE })
public class ProductController {
private final Logger LOG = LoggerFactory.getLogger(this.getClass());
@Autowired
private ProductService productService;
// 这种写法感觉不太好维护,因为可能代码里面到处都是,还是统一在xml文件中写感觉比较好
@Reference(url = "dubbo://127.0.0.1:20880", interfaceName = "cn.cuit.user.center.api.UserService", version = "1.0")
private UserService userService;
@GET
@Path("/{id:[a-zA-Z0-9]+}")
public Product getProductById(@PathParam("id") String id) {
LOG.info(">>>>>>>>>>id = {}", id);
return productService.getProductById(id);
}
// 请求路径为:localhost:8081/product/api/products/testCallUserService
@GET
@Path("/testCallUserService")
public String testCallUserService() {
return userService.testCallUserService();
}
@GET
@Path("/getUserByUsername/{username}")
public User getUserByUsername(@PathParam("username") String username) {
return userService.getUserByUsername(username);
}
}
Service实现
package cn.cuit.product.center.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import com.alibaba.dubbo.config.annotation.Service;
import cn.cuit.product.center.api.ProductService;
import cn.cuit.product.center.model.Product;
@Component
@Service(version = "${product.service.version}")
public class ProductServiceImpl implements ProductService {
private static final Logger LOG = LoggerFactory.getLogger(ProductServiceImpl.class);
// @SentinelResource(value = "testSentinel", fallback = "doFallback",
// blockHandler = "exceptionHandler")
public Product getProductById(String id) {
LOG.info("..........id = {}", id);
Product product = new Product();
product.setName("CUIT -> " + id);
product.setPrice(19999);
return product;
}
}
启动测试:
首先看看两个服务都是启动成功的
也可以在Dubbo的admin控制台去查看:
Dubbo控制台搭建参考:https://blog.csdn.net/weixin_42465125/article/details/88184452
好了,接下来先单独测试product-center
访问:http://localhost:8081/product/api/products/1
然后测试远程调用UserService
访问:http://localhost:8081/product/api/products/testCallUserService
访问:http://localhost:8081/product/api/products/getUserByUsername/remoteCall
代码地址:https://github.com/CUITLLB/jax-rs-dubbo-demo
********************************* 不积跬步无以至千里,不积小流无以成江海 *********************************