有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我目前正在做关于客户机和服务器主题的家庭作业: 我创建了一个名为VehileRequest.java的类,它将从Client.java中获取三个变量(年份、品牌、模型),并将它们传递给Server.java,然后Server将从VehicleRespone.java中获取信息,并显示有关价格、里程和价格的信息

据我所知,程序无法识别传递到响应文件的请求

我无法将请求传递给响应,以便响应能够理解。请帮忙。多谢各位

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

共 (2) 个答案

  1. # 1 楼答案

    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();
            }
        }
    }
    
  2. # 2 楼答案

    尽管João Dias already solved your lapse by fixing the response-type,我还是想分享一些关于JSON转换的实用建议,特别是在实现web API facades时,比如您的Client/Server类:

    1. 带有参数的纯函数使代码更易于测试:send(request)
    2. 内容转换(从/转换为格式,如JSON)是一个(交叉)独立的问题:将可重用组件(如^{)注入客户机和服务器(表示层),使请求/响应类与格式无关

    生成的代码可能会对您有吸引力

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

    请求响应:send作为纯函数

    通常,客户机的职责是发送多个不同的请求。因此,请参数化send方法

    设计问题

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

    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:它通常将一个输入转换为一个新的输出——它产生一些东西,比如响应

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

    改善

    After:添加参数以使不同的request可测试。方法名称简化

    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,以及二进制格式,通常由称为Separation of Concerns的设计原则处理。特别是在web应用程序(如简化的客户机-服务器体系结构)中,这会导致不同的层(最佳实践):

    • 表示层(涉及UI、Web、通信)。。e、 g.您的Client/Server类和Jackson的ObjectMapper处理JSON转换
    • 业务层(与逻辑有关)。。e、 g.你的Vehicle..
    • 持久层(涉及存储、数据库等)

    请参见这些单独的关注点,如维基百科Multi-tier Architecture或罗伯特·C·马丁的Clean Architecture中的分层说明

    设计问题

    外部依赖项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>
       }
    }
    

    通过这种方式,您可以在main方法中通过如下配置创建一个支持XML的特殊客户机 Client xmlClient = new Client(new XmlMapper())或按原样使用(JSON作为内容交换格式):Client client = new Client(new ObjectMapper())


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

    然而,在“真正的代码”中,正如在像Spring这样的专业web框架中所看到的,这是良好或最佳实践,有助于可扩展和可维护的软件,请参见SOLID