《服务计算基础》作业1

《服务计算基础》这门课质量是很高,但是课程作业也可以说是非常折磨人。作业里要求编程的内容并不多,但是每个实验都需要配置环境,非常的麻烦。所以把这个作业的实验报告稍加修改,作为一篇博客发表,希望可以帮助到后来的人。

服务计算基础 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来获取这些属性,输出在屏幕上。

在IDEA下运行的结果

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发送请求就可以调用相应的函数。对于setters,要求客户端使用POST方法来提交参数,对于getters,要求客户端使用GET方法来获取。为了方便实验结果的测试,将这三个函数整合成一个set方法,同时设置三个字段的值,并通过sayhello方法同时返回给客户端。

实验结果

使用postman来发送POST和GET请求。

首先通过带参数的POST方法来设置字段(调用Person类的set方法):

POST方法设置字段

可以看到,返回的状态码为200,成功地设置了相应的字段。

再调用GET方法来获得一个招呼(调用Person类的sayhello方法):

通过GET方法获取字段

可以看到,返回的状态码为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();
}
}
}

输出结果如下:

使用Java客户端的实验结果

Solution for Homework 1.3

环境配置

安装Tomcat 8.5

https://tomcat.apache.org/ 下载安装包后,安装到本地,并配置%CATALINA_HOME%等环境变量,运行Startup.bat脚本。在浏览器访问http://localhost:8080/ ,出现如下页面,说明服务端运行成功。

Tomcat页面

安装Axis2

从官网https://axis.apache.org/axis2/java/core/download.html 下载axis2.war,将该文件复制到Tomcat安装目录下的Webapps文件夹中,重新运行客户端。运行后发现Webapps目录下多出axis2目录,并且访问http://localhost:8080/axis2/ ,显示以下页面,说明axis2安装成功。

Axis2页面

还需要下载Axis2提供的wsdl2java脚本,该脚本在https://axis.apache.org/axis2/java/core/download.html 提供的``axis2-1.8.2-bin.zip中,解压该压缩包,配置环境变量%AXIS_HOME%,在命令行输入wsdl2java`,出现以下提示,说明脚本配置成功。

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");
}
}

输入以下命令编译代码:

1
javac Person.java

生成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"?>
<!--这里scope的作用是保持Person类的生命周期保持在整个服务端执行期间-->
<service name="PersonService" scope="application">
<description>一个简单的WebService</description>
<!-- 必须和上面那个java代码的包名一致-->
<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文件:

1
jar -cvf Person.aar . .

就会在当前目录生成一个Person.aar文件。

部署服务

将上一节生成的Person.aar文件复制到axis2/WEB-INF/services目录下,重新运行Tomcat服务端,并访问http://localhost:8080/axis2/services/listServices ,看到页面中出现了我们配置的PersonService服务。

配置完后的Axis

点击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的要求,需要改变一下目录结构:

IDEA项目结构

并且发现代码中缺少依赖,可以从官网下载,也可以使用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();
}
}
}

实验结果

构建并运行客户端,输出结果如下:

实验结果


《服务计算基础》作业1
http://zhouhf.top/2024/10/29/service-computing-homework1/
作者
周洪锋
发布于
2024年10月29日
许可协议