如何将输入转换为程序可以理解的方法

How to convert an input into a method that the program will understand

我目前正在做关于客户端和服务器主题的作业: 我创建了一个名为 VehileRequest.java 的 class,它将从 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;
    }
}

这是 VehicleRequest 文件

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

虽然 , I would like to share some practical advice on JSON-conversion especially when implementing web-API facades 喜欢你的 Client / Server classes:

  1. 带参数的纯函数使代码更易于测试:send(request)
  2. content-conversion(from/into 格式,如 JSON)是一个(交叉)单独关注点:注入一个可重用的组件,如 ObjectMapper 到客户端和服务器(表示层),使您的 request/response classes 格式独立

生成的代码可能对您有吸引力,因为

  • 更具可读性
  • 更容易理解和调试
  • 少耦合
  • 更易于维护和扩展

请求响应:send作为纯函数

通常一个客户端的职责是发送多个不同的请求。所以参数化你的 send 方法。

设计问题

之前:没有参数,只有静态硬编码请求。因此不可测试。

public VehicleRequest sendRequest() throws Exception {
    out.println(VehicleRequest.toJSON(new VehicleRequest(2008,"Honda","Civic")));
    return VehicleRequest.fromJSON(in.readLine());
}

注意:方法签名...Request sendRequest() 可以读作“output = produceInput()”。这种设计方法或函数的风格被称为 pure function:它通常将输入转换为新的输出 - 它会产生一些东西,比如响应。

设计问题: 这里不能输入。返回的产品或答案可能总是相同的。您不想提出不同的问题或发送不同的请求吗?这样预期的答案取决于给定的请求。

改善

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

public VehicleResponse send(VehicleRequest request) throws Exception {
    out.println(VehicleRequest.toJSON(request));
    return VehicleResponse.fromJSON(in.readLine());
}

这可以在您的 mainresponse = client.send(new VehicleRequest(2008,"Honda","Civic")).

等测试中调用

对象表示:JSON-转换为单独关注

有一些基本的表示格式,如 String 与每个 class 紧密耦合。在 Java 中,这个 关注点 继承自 Object class 的方法 toString() 并且对于一些包装器-classes像 Integer.valueOf(String s).

但是更复杂的表示,尤其是与 REST 或 HTTP 相关的 JSONXMLHTML,还有二进制格式通常由称为 Separation of Concerns 的设计原则处理。特别是在 Web 应用程序中(比如简化的客户端-服务器架构),这会导致分离层(最佳实践):

  • 表示层(关注 UI、Web、通信).. 例如您的 Client / Server classes 和 Jackson 的 ObjectMapper 处理 JSON-conversion
  • 业务层(关注逻辑).. 例如你的 Vehicle.. classes
  • 持久层(关注存储、数据库等)

将这些单独的关注点显示为层,例如在维基百科中 Multi-tier Architecture or in Robert C. Martin's Clean Architecture.

设计问题

外部依赖 Jackson 是您的 DTO-class 的重复部分,例如 ..Request..Response。所以两者都取决于 Jackson 和 JSON-格式。

之前:表示层的关注点混合到DTO-classes中,这可能会随着业务层的变化而变化。现在他们需要改变每种格式,客户端也可以支持(强耦合和 2 个改变的原因)。

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

注意:您可以将此横切关注点(许多 classes 使用)移至客户端。这样,您的(实体)classes 将独立于 format/mapping-framework,并且客户端可以在将来轻松扩展以支持其他格式(如 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>
   }
}

这样你就可以在你的主方法中简单地创建一个特殊的 XML-capable 客户端通过配置像 Client xmlClient = new Client(new XmlMapper()) 或按原样使用(使用 JSON 作为内容交换格式):Client client = new Client(new ObjectMapper()).


对于你的 CS 课程和家庭作业,这可能是太多和过度工程化了。

然而,在“真实代码”中,如 Spring 等专业网络框架中所见,这是好的或最佳实践,有助于开发可扩展和可维护的软件,请参见 SOLID