如何将输入转换为程序能够理解的方法



我目前正在做关于客户端和服务器主题的作业:我创建了一个名为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"
}

如果我正确理解您的代码,您正在尝试在ClientServer之间进行通信。在这种情况下,您需要更改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类:

  1. 带有参数的纯函数使代码更易于测试:send(request)
  2. 内容转换(从格式转换为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()";。这种设计方法或函数的风格被称为纯函数:它通常将输入转换为新的输出——它产生一些东西,比如响应。

设计问题:此处无法提供任何输入。返回的产品或答案可能总是相同的。你不想问不同的问题或发送不同的请求吗。因此,预期的答案取决于给定的请求。

改进

之后:添加了参数,使其可以用不同的requests进行测试。方法名称简化。

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相关的表示,如JSONXMLHTML,以及二进制格式,通常由一种称为关注点分离的设计原则来处理。特别是在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。

最新更新