我目前正在做关于客户端和服务器主题的作业:我创建了一个名为VehileRequest.java
的类,它将从Client.java
获取三个变量(年份、品牌、型号),并将它们传递给Server.java
,然后Server
将从VehicleRespone.java
获取信息,并显示有关价格、里程vv。。。
据我所知,程序无法识别传递到响应文件的请求。
我一直在把请求传递给响应,以便响应能够理解。请帮忙。谢谢
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
public class VehicleResponse {
private VehicleRequest request;
private int milesOnVehicle;
private int price;
private int numberOfSeats;
private int numberOfDoors;
private String[] options;
@JsonIgnore
private static final ObjectMapper objectMapper = new ObjectMapper();
public static String toJSON(VehicleResponse vehicle) throws Exception {
return objectMapper.writeValueAsString(vehicle);
}
public static VehicleResponse fromJSON(String input) throws Exception{
return objectMapper.readValue(input, VehicleResponse.class);
}
protected VehicleResponse() {}
public VehicleResponse(VehicleRequest request, int milesOnVehicle,int price, int numberOfSeats, int numberOfDoors,String[] options) {
this.request=request;
this.milesOnVehicle=milesOnVehicle;
this.price=price;
this.numberOfSeats=numberOfSeats;
this.numberOfDoors=numberOfDoors;
this.options=options;
}
@Override
public String toString() {
return String.format(
"Vehicle request:[miles=%d, price=%d, number of seats=%d,number of doors=%d, option='%s']",
milesOnVehicle,price,numberOfSeats,numberOfDoors,options);
}
public VehicleRequest getRequest() {return request;}
public int getMilesOnVehicle(){return milesOnVehicle;};
public int getPrice(){return price;}
public int getNumberOfDoors() {return numberOfDoors;}
public int getNumberOfSeats() {return numberOfSeats;}
public String[] getOptions() {return options;}
public void setRequest(VehicleRequest request) {
this.request = request;
}
public void setMilesOnVehicle(int milesOnVehicle) {
this.milesOnVehicle = milesOnVehicle;
}
public void setPrice(int price) {
this.price = price;
}
public void setNumberOfSeats(int numberOfSeats) {
this.numberOfSeats = numberOfSeats;
}
public void setNumberOfDoors(int numberOfDoors) {
this.numberOfDoors = numberOfDoors;
}
public void setOptions(String[] options) {
this.options = options;
}
}
这是车辆请求文件
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
public class VehicleRequest {
private int year;
private String make;
private String model;
@JsonIgnore
private static final ObjectMapper objectMapper = new ObjectMapper();
public static String toJSON(VehicleRequest vehicle) throws Exception {
return objectMapper.writeValueAsString(vehicle);
}
public static VehicleRequest fromJSON(String input) throws Exception{
return objectMapper.readValue(input, VehicleRequest.class);
}
protected VehicleRequest() {}
public VehicleRequest(int year, String make, String model) {
this.year = year;
this.make =make;
this.model=model;
}
@Override
public String toString() {
return String.format(
"Vehicle: [year=%d, make='%s', model='%s']",
year,make,model);
}
public int getYear() {
return year;
}
public String getMake(){return make;}
public String getModel(){return model;}
public void setYear(int year) {
this.year = year;
}
public void setMake(String make){
this.make=make;
}
public void setModel(String model){
this.model=model;
}
}
这是服务器
public class Server {
private ServerSocket serverSocket;
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void start(int port) throws Exception {
serverSocket = new ServerSocket(port);
clientSocket = serverSocket.accept();
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
VehicleRequest request = VehicleRequest.fromJSON(inputLine);
VehicleResponse response = new VehicleResponse(request,10000,12000,5,4, null);
out.println(VehicleResponse.toJSON(response));
}
}
public void stop() throws IOException {
in.close();
out.close();
clientSocket.close();
serverSocket.close();
}
public static void main(String[] args) {
Server server = new Server();
try {
server.start(4444);
server.stop();
} catch(Exception e) {
e.printStackTrace();
}
}
}
这是客户端
public class Client {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void startConnection(String ip, int port) throws IOException {
clientSocket = new Socket(ip, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
public VehicleRequest sendRequest() throws Exception {
out.println(VehicleRequest.toJSON(new VehicleRequest(2008,"Honda","Civic")));
return VehicleRequest.fromJSON(in.readLine());
}
public void stopConnection() throws IOException {
in.close();
out.close();
clientSocket.close();
}
public static void main(String[] args) {
Client client = new Client();
try {
client.startConnection("127.0.0.1", 4444);
System.out.println(client.sendRequest().toString());
client.stopConnection();
} catch(Exception e) {
e.printStackTrace();
}
}
}
我得到的结果是
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "request" (class edu.sdccd.cisc191.template.VehicleRequest), not marked as ignorable (3 known properties: "model", "year", "make"])
at [Source: (String)"{"request":{"year":2008,"make":"Honda","model":"Civic"},"milesOnVehicle":10000,"price":12000,"numberOfSeats":5,"numberOfDoors":4,"options":null}"; line: 1, column: 13] (through reference chain: edu.sdccd.cisc191.template.VehicleRequest["request"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:61)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:855)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1212)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1604)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1582)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:299)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:156)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3434)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3402)
at edu.sdccd.cisc191.template.VehicleRequest.fromJSON(VehicleRequest.java:17)
at edu.sdccd.cisc191.template.Client.sendRequest(Client.java:32)
at edu.sdccd.cisc191.template.Client.main(Client.java:44)
}
在VehicleRequest.fromJSON(in.readLine());
行中,您试图解析任何输入,它似乎是:
{
"request":{
"year":2008,
"make":"Honda",
"model":"Civic"
},
"milesOnVehicle":10000,
"price":12000,
"numberOfSeats":5,
"numberOfDoors":4,
"options":null
}
然而,您希望它可以解析为VehicleRequest
,这是不可能的,因为它只包含3个参数,而不是全部。要么将其解析为VehicleResponse
,如下所示:
VehicleResponse.fromJSON(in.readLine());
或者您将输入更改为可以解析为VehicleRequest
:的内容
{
"year":2008,
"make":"Honda",
"model":"Civic"
}
如果我正确理解您的代码,您正在尝试在Client
和Server
之间进行通信。在这种情况下,您需要更改Client
代码:
public class Client {
private Socket clientSocket;
private PrintWriter out;
private BufferedReader in;
public void startConnection(String ip, int port) throws IOException {
clientSocket = new Socket(ip, port);
out = new PrintWriter(clientSocket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
public VehicleResponse sendRequest() throws Exception {
out.println(VehicleRequest.toJSON(new VehicleRequest(2008,"Honda","Civic")));
return VehicleResponse.fromJSON(in.readLine());
}
public void stopConnection() throws IOException {
in.close();
out.close();
clientSocket.close();
}
public static void main(String[] args) {
Client client = new Client();
try {
client.startConnection("127.0.0.1", 4444);
System.out.println(client.sendRequest().toString());
client.stopConnection();
} catch(Exception e) {
e.printStackTrace();
}
}
}
虽然João Dias已经通过修复响应类型解决了您的失误,但我想分享一些关于JSON-转换的实用建议,尤其是在实现web-API外观时,如Client
/Server
类:
-
带有参数的纯函数使代码更易于测试:
send(request)
- 内容转换(从格式转换为JSON等格式)是一个(交叉)单独的问题:将
ObjectMapper
等可重用组件注入客户端和服务器(表示层),使您的请求/响应类与格式无关
生成的代码可能会作为吸引您
- 可读性更强
- 更易于理解和调试
- 较少耦合
- 更易于维护和扩展
请求响应:send
作为纯函数
通常,客户端的职责是发送多个不同的请求。因此,将send
方法参数化。
设计问题
之前:没有参数,但静态硬编码请求。因此不可测试。
public VehicleRequest sendRequest() throws Exception {
out.println(VehicleRequest.toJSON(new VehicleRequest(2008,"Honda","Civic")));
return VehicleRequest.fromJSON(in.readLine());
}
注意:方法签名CCD_;output=productionInput()";。这种设计方法或函数的风格被称为纯函数:它通常将输入转换为新的输出——它产生一些东西,比如响应。
设计问题:此处无法提供任何输入。返回的产品或答案可能总是相同的。你不想问不同的问题或发送不同的请求吗。因此,预期的答案取决于给定的请求。
改进
之后:添加了参数,使其可以用不同的request
s进行测试。方法名称简化。
public VehicleResponse send(VehicleRequest request) throws Exception {
out.println(VehicleRequest.toJSON(request));
return VehicleResponse.fromJSON(in.readLine());
}
这可以在main
中调用,也可以在类似response = client.send(new VehicleRequest(2008,"Honda","Civic"))
的测试中调用。
对象表示:JSON转换作为单独的关注点
有一些基本的表示格式,如String
,与每个类紧密耦合。在Java中,这个关注点是从Object
类的方法toString()
和一些包装类(如Integer.valueOf(String s)
)继承而来的。
然而,更复杂的表示,尤其是与REST或HTTP相关的表示,如JSON、XML
、HTML
,以及二进制格式,通常由一种称为关注点分离的设计原则来处理。特别是在web应用程序(如简化的客户端-服务器体系结构)中,这会导致单独的层(最佳实践):
- 表示层(关注UI、Web、通信)。。例如,您的
Client
/Server
类和Jackson的ObjectMapper
处理JSON转换 - 业务层(关注逻辑)。。例如您的
Vehicle..
类 - 持久层(涉及存储、数据库等)
请参阅这些单独的关注点,如维基百科多层体系结构或Robert C.Martin的清洁体系结构。
设计问题
外部依赖Jackson是DTO类(如..Request
和..Response
)的重复部分。所以两者都依赖于Jackson和JSON格式。
之前:表示层的关注点被混合到DTO类中,这可能会随着业务层的变化而变化。现在,它们需要根据每种格式进行更改,客户端也可以支持(强耦合和两个更改原因)。
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
// ..
@JsonIgnore
private static final ObjectMapper objectMapper = new ObjectMapper();
// duplicated code, implemented similarly for both classes
public static String toJSON(VehicleRe.. vehicle) throws Exception {
return objectMapper.writeValueAsString(vehicle);
}
public static VehicleRe.. fromJSON(String input) throws Exception{
return objectMapper.readValue(input, VehicleRe.. .class);
}
注意:您可以将这个横切(被许多类使用)关注点移动到客户端中。通过这种方式,您的(实体)类与格式/映射框架保持独立,并且客户端可以很容易地扩展到将来支持其他格式(如XML)。
改进
之后:在REST中,格式是表示层关心的问题。客户端负责内容协商和转换。
class Client {
private final ObjectMapper mapper;
// Mapper can be injected as dependency, configurable from ouside
public Client(ObjectMapper mapper) {
this.mapper = mapper;
// optional remaining initialization, could add ip, port, etc.
}
public VehicleResponse send(VehicleRequest vehicle) throws Exception {
String request = objectMapper.writeValueAsString(vehicle); // to <textual-format>
out.println(request); // request as String (now JSON, future XML)
String response = in.readLine(); // request as String (now JSON, future XML)
return objectMapper.readValue(response); // from <textual-format>
}
}
通过这种方式,您可以在主方法中通过配置Client xmlClient = new Client(new XmlMapper())
或按原样使用(以JSON作为内容交换格式):Client client = new Client(new ObjectMapper())
。
对于你的CS课程和家庭作业来说,这可能太多了,过于工程化。
然而,在";实代码";,正如在Spring
这样的专业web框架中看到的那样,这是一种好的或最佳的实践,有助于开发可扩展和可维护的软件,请参阅SOLID。