《服务计算基础》这门课质量是很高,但是课程作业也可以说是非常折磨人。作业里要求编程的内容并不多,但是每个实验都需要配置环境,非常的麻烦。所以把这个作业的实验报告稍加修改,作为一篇博客发表,希望可以帮助到后来的人。
服务计算基础 Homework1
作业1: 服务开发和调用
1 2 3 4 5 6 7 8 9 10 11 12 13 >Class person >{ String name;int age;boolean gender; set/get Name () ; set/get Age () ; set/get Gender () ;String sayHello () { Return “Hello world!”+name; } >}
1.1 基于Apache Dubbo 将上述类的方法对外提供RPC服务并调用;
1.2 基于Java Spring将上述类的方法对外提供RESTful服务并调用;
1.3 基于Apache Axis2将上述类的方法对外提供Web服务,生成WSDL文件,以及调用服务。
Solution for Homework 1.1
环境配置
在Windows操作系统下进行开发,集成开发环境为IDEA。在IDEA下创建一个Maven项目,并编写pom.xml
,在其中添加如下的依赖:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <properties > <project.build.sourceEncoding > UTF-8</project.build.sourceEncoding > <dubbo.version > 3.3.0-beta.1</dubbo.version > <log4j2.version > 2.20.0</log4j2.version > </properties > <dependencies > <dependency > <groupId > org.apache.dubbo</groupId > <artifactId > dubbo</artifactId > <version > 3.3.0</version > </dependency > <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-slf4j-impl</artifactId > <version > ${log4j2.version}</version > </dependency <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-core</artifactId > <version > ${log4j2.version}</version > </dependency > <dependency > <groupId > org.apache.logging.log4j</groupId > <artifactId > log4j-api</artifactId > <version > ${log4j2.version}</version > </dependency > </dependencies >
为了简易起见,本次实验仅使用Dubbo的纯原生API,不使用SpringBoot,所以只需要引入一个轻量的Dubbo
依赖,以及用于打印日志的Log4j
即可。
编写接口
使用Java语言编写题设要求的接口:
1 2 3 4 5 6 7 8 9 public interface PersonService { String sayHello () ; void setName (String name) ; void setAge (int age) ; void setGender (boolean gender) ; String getName () ; int getAge () ; boolean getGender () ; }
并编写一个实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 package org.hello.entity;import org.hello.interfaces.PersonService;public class Person implements PersonService { private String name; private int age; private boolean gender; @Override public void setName (String name) { this .name = name; } @Override public void setAge (int age) { this .age = age; } @Override public void setGender (boolean gender) { this .gender = gender; } @Override public String getName () { return this .name; } @Override public int getAge () { return this .age; } @Override public boolean getGender () { return this .gender; } @Override public String sayHello () { return "Hello world! " + this .name; } }
服务端
编写服务端,本次实验设计服务端在端口50052上运行,客户端可以访问50052端口来获取PersonService
服务:
1 2 3 4 5 6 7 8 9 10 public class Server { public static void main (String[] args) { DubboBootstrap.getInstance() .application(ApplicationBuilder.newBuilder().name("dubbo-samples-api" ).logger("slf4j" ).build()) .protocol(new ProtocolConfig(CommonConstants.TRIPLE, 50052 )) .service(ServiceBuilder.newBuilder().interfaceClass(PersonService.class).ref(new Person()).build()) .start() .await(); } }
客户端
令客户端连接本地的50052端口,然后从键盘读取输入,调用服务端提供的一系列接口函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class Client { public static void main (String[] args) { PersonService personService = (PersonService) ReferenceBuilder.newBuilder() .interfaceClass(PersonService.class) .url("tri://localhost:50052" ) .build() .get(); Scanner scanner = new Scanner(System.in); System.out.println("What's your name?" ); String name = scanner.next(); System.out.println("What's your age?" ); int age = scanner.nextInt(); System.out.println("Are you a boy?" ); String answer = scanner.next(); boolean isBoy = answer.equals("Yes" )||answer.equals("yes" ); personService.setName(name); personService.setAge(age); personService.setGender(isBoy); System.out.printf("Hello %s, you are a %s, your age is %d.\n" , personService.getName(),personService.getGender() ? "Boy" : "Girl" ,personService.getAge()); } }
实验结果
设计了一个类似问答的程序,客户端通过调用服务端提供的setter
来设置各个字段的属性,并再次调用服务端的getter
来获取这些属性,输出在屏幕上。
Solution for Homework 1.2
环境配置
在IDEA中新建一个Spring Boot
工程,然后引入Spring web
依赖。
编写接口
接口编写与上文相同,这里略去,但是需要在实现中为类和方法添加注解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 @RestController public class PersonController implements PersonService { private String name; private int age; private boolean gender; @PostMapping("/name") @Override public void setName (@RequestParam String name) { this .name = name; } @PostMapping("/age") @Override public void setAge (@RequestParam int age) { this .age = age; } @PostMapping("/gender") @Override public void setGender (boolean gender) { this .gender = gender; } @GetMapping("/name") @Override public String getName () { return this .name; } @GetMapping("/age") @Override public int getAge () { return this .age; } @GetMapping("/gender") @Override public boolean getGender () { return this .gender; } @PostMapping("/set") public void set (@RequestParam String name, @RequestParam int age, @RequestParam boolean gender) { this .name = name; this .age = age; this .gender = gender; } @GetMapping("/sayhello") @Override public String sayHello () { return String.format("Hello %s! Your age is %d, your gender is %s" , name, age, gender? "boy" :"girl" ); } }
只需要对相应的URI发送请求就可以调用相应的函数。对于setter
s,要求客户端使用POST方法来提交参数,对于getter
s,要求客户端使用GET方法来获取。为了方便实验结果的测试,将这三个函数整合成一个set
方法,同时设置三个字段的值,并通过sayhello
方法同时返回给客户端。
实验结果
使用postman
来发送POST和GET请求。
首先通过带参数的POST方法来设置字段(调用Person
类的set
方法):
可以看到,返回的状态码为200,成功地设置了相应的字段。
再调用GET方法来获得一个招呼(调用Person
类的sayhello
方法):
可以看到,返回的状态码为200,并且返回的响应体中也包含了我们预期的内容。
也可以使用Java来发送GET请求和POST请求,实现在本地代码中调用远程服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 package org.zhouf.restfuldemo.client;import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;public class Client { private static final String BASE_URL = "http://localhost:8080" ; public static void main (String[] args) { try { setName("John" ); setAge(30 ); setGender(true ); System.out.println(getName()); System.out.println(getAge()); System.out.println(getGender()); System.out.println(sayHello()); } catch (Exception e) { e.printStackTrace(); } } public static void setName (String name) throws Exception { sendPostRequest("/name" , "name=" + name); } public static void setAge (int age) throws Exception { sendPostRequest("/age" , "age=" + age); } public static void setGender (boolean gender) throws Exception { sendPostRequest("/gender" , "gender=" + gender); } public static String getName () throws Exception { return sendGetRequest("/name" ); } public static String getAge () throws Exception { return sendGetRequest("/age" ); } public static String getGender () throws Exception { return sendGetRequest("/gender" ); } public static String sayHello () throws Exception { return sendGetRequest("/sayhello" ); } private static void sendPostRequest (String endpoint, String params) throws Exception { URL url = new URL(BASE_URL + endpoint); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST" ); conn.setDoOutput(true ); conn.setRequestProperty("Content-Type" , "application/x-www-form-urlencoded" ); try (OutputStream os = conn.getOutputStream()) { os.write(params.getBytes()); os.flush(); } conn.getResponseCode(); } private static String sendGetRequest (String endpoint) throws Exception { URL url = new URL(BASE_URL + endpoint); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET" ); try (BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null ) { response.append(inputLine); } return response.toString(); } } }
输出结果如下:
Solution for Homework 1.3
环境配置
安装Tomcat 8.5
从https://tomcat.apache.org/ 下载安装包后,安装到本地,并配置%CATALINA_HOME%
等环境变量,运行Startup.bat
脚本。在浏览器访问http://localhost:8080/ ,出现如下页面,说明服务端运行成功。
安装Axis2
从官网https://axis.apache.org/axis2/java/core/download.html 下载axis2.war
,将该文件复制到Tomcat安装目录下的Webapps文件夹中,重新运行客户端。运行后发现Webapps目录下多出axis2目录,并且访问http://localhost:8080/axis2/ ,显示以下页面,说明axis2安装成功。
还需要下载Axis2提供的wsdl2java
脚本,该脚本在https://axis.apache.org/axis2/java/core/download.html 提供的``axis2-1.8.2-bin.zip中,解压该压缩包,配置环境变量
%AXIS_HOME%,在命令行输入
wsdl2java`,出现以下提示,说明脚本配置成功。
编写代码 生成服务
按照1.1 1.2提到的方法编写Person类代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 package org.zhouhf;public class Person { private String name; private int age; private boolean gender; public void setName (String name) { this .name = name; } public void setAge (int age) { this .age = age; } public void setGender (boolean gender) { this .gender = gender; } public String getName () { return this .name; } public int getAge () { return this .age; } public boolean getGender () { return this .gender; } public String sayHello () { return String.format("Hello %s! Your age is %d, your gender is %s" , name, age, gender? "boy" :"girl" ); } }
输入以下命令编译代码:
生成Person.class
文件,我们手动将其放到org/zhouhf
下,以匹配包名。
为了顺利发布Axis2
服务,还需要在根目录下新建一个META-INFO
文件夹,然后在文件夹中新建一个services.xml
,其内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?xml version="1.0" encoding="UTF-8"?> <service name ="PersonService" scope ="application" > <description > 一个简单的WebService</description > <parameter name ="ServiceClass" > org.zhouhf.Person</parameter > <operation name ="getAge" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > <operation name ="setAge" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > <operation name ="setName" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > <operation name ="getName" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > <operation name ="setGender" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > <operation name ="getGender" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > <operation name ="sayHello" > <messageReceiver mep ="http://www.w3.org/2004/08/wsdl/in-out" class ="org.apache.axis2.rpc.receivers.RPCMessageReceiver" /> </operation > </service >
新建完这几个文件后,目录结构如下:
随后将这个项目打包成一个aar
文件:
就会在当前目录生成一个Person.aar
文件。
部署服务
将上一节生成的Person.aar
文件复制到axis2/WEB-INF/services
目录下,重新运行Tomcat服务端,并访问http://localhost:8080/axis2/services/listServices ,看到页面中出现了我们配置的PersonService
服务。
点击PersonService
就可以看到生成的wsdl
文件了。我们可以在地址栏输入http://localhost:8080/axis2/services/PersonService/getAge
来测试,输入后浏览器返回的xml文档如下:
1 2 3 <ns:getAgeResponse xmlns:ns ="http://zhouhf.org" > <ns:return > 0</ns:return > </ns:getAgeResponse >
尝试调用setAge
函数:http://localhost:8080/axis2/services/PersonService/setAge?args0=25
,然后再次调用getAge
,返回值如下:
1 2 3 <ns:getAgeResponse xmlns:ns ="http://zhouhf.org" > <ns:return > 25</ns:return > </ns:getAgeResponse >
要想达到该效果,必须要在services.xml
中将服务的生命周期声明为application
。
客户端
要编写客户端,必须先将``wsdl文件转化成java代码,这里就要使用前面配置的
wsdl2java`脚本,新建一个java项目,在项目根目录输入:
1 wsdl2java -uri http://localhost:8080/axis2/services/PersonService?wsdl -p org.zhouhf -o .
uri
用于指定wsdl
的位置,-p
用于指定生成的java文件的包名,-o
用于指定输出目录。
生成java代码后,在IDEA中打开,发现目录不符合Maven的要求,需要改变一下目录结构:
并且发现代码中缺少依赖,可以从官网下载,也可以使用Maven来管理依赖:
1 2 3 4 5 6 7 <dependencies > <dependency > <groupId > org.apache.axis2</groupId > <artifactId > org.apache.axis2.osgi</artifactId > <version > 1.8.2</version > </dependency > </dependencies >
客户端的环境配置完成后就可以开始编写测试程序了。
测试程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package org.zhouhf;public class Main { public static void main (String[] args) { try { String serviceURL = "http://localhost:8080/axis2/services/PersonService" ; PersonServiceStub stub = new PersonServiceStub(serviceURL); PersonServiceStub.SetAge setAgeRequest = new PersonServiceStub.SetAge(); setAgeRequest.setArgs0(25 ); stub.setAge(setAgeRequest); PersonServiceStub.SetName setNameRequest = new PersonServiceStub.SetName(); setNameRequest.setArgs0("Zhou hongfeng" ); stub.setName(setNameRequest); PersonServiceStub.SetGender setGenderRequest = new PersonServiceStub.SetGender(); setGenderRequest.setArgs0(true ); stub.setGender(setGenderRequest); PersonServiceStub.SayHello sayHelloRequest = new PersonServiceStub.SayHello(); PersonServiceStub.SayHelloResponse sayHelloResponse = stub.sayHello(sayHelloRequest); System.out.println(sayHelloResponse.get_return()); } catch (Exception e) { e.printStackTrace(); } } }
实验结果
构建并运行客户端,输出结果如下: