【问题标题】:Java WebApp keeps returning same resultsJava WebApp 不断返回相同的结果
【发布时间】:2020-01-02 10:59:21
【问题描述】:

我编写了这个 Web 应用程序,在输入城市坐标(纬度、经度)后(来源:json)返回美国最近发生的 10 次地震的列表。现在,我有两个问题:

问题 1.

  1. 我输入了所选城市(例如西雅图)的坐标,我得到了正确的结果。
  2. 我输入第二个城市(例如华盛顿特区)的坐标,我得到不同的(正确的)结果。
  3. 我输入与第一个城市(例如西雅图)相同的坐标,结果与之前的第二次搜索相同。
  4. 我输入第三、第四、第六等城市的坐标,我一直得到相同的结果。

就像应用程序被卡住了(经过 2-3 次正确查询?)。有时我连续得到三个不同的结果,有时是四个,有时只打印两个,然后打印相同的结果。如果我将坐标硬编码到 Servlet 到 Java 方法中,每次结果都不同,所以我猜测将输入字段传递到 Java 方法中存在一些问题。 无论是我从列表中选择城市还是我自己输入坐标都没有关系。

问题 2。

  1. 我从下拉列表中选择一个城市。
  2. 坐标正在输入到输入 html 表单中,例如堪萨斯城:纬度:39.099728 经度 -94.578568。
  3. 我在纬度上添加字母/符号,例如39.099728sdjfhjsdf,经度:-94.578568 然后我按下提交
  4. 我收到有关字段格式不正确的信息(到目前为止还可以)。
  5. 我从下拉列表中选择了另一个城市,输入字段正在填充新坐标,然后我按下提交,但我不断收到警告,数字格式不正确(甚至像程序一样虽然输入是新的,但仍会显示 39.099728sdjfhjsdf)。

这是最小的工作示例。项目用 Eclipse 编写。

ReadLongitudeAndLatitudeServlet.java

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dominikazb.earthquakes.engine.ReadJsonFile;

@WebServlet("/read")
public class ReadLongitudeAndLatitudeServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String latitudeOfSearchedCityString = request.getParameter("latitudeOfSearchedCity");
    String longitudeOfSearchedCityString = request.getParameter("longitudeOfSearchedCity");
    ReadJsonFile.getReadJson().convertJsonToJavaObjects(latitudeOfSearchedCityString, longitudeOfSearchedCityString);
    response.sendRedirect("list");
}
}

PrintEarthquakesServlet.java

import java.io.IOException;
import java.util.TreeMap;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.dominikazb.earthquakes.engine.ReadJsonFile;

@WebServlet("/list")
public class PrintEarthquakesServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    TreeMap<Double, String> outputMap = ReadJsonFile.getReadJson().read10closestCities();
    request.setAttribute("outputMap", outputMap);
    request.getRequestDispatcher("/earthquakesList.jsp").forward(request, response);
}
}

ReadJsonFile.java

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.annotate.JsonIgnoreProperties;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

@JsonIgnoreProperties(ignoreUnknown = true)
public class ReadJsonFile {

    private static ReadJsonFile readJson = new ReadJsonFile();  
    private static String place;
    private static double longitude;
    private static double latitude; 
    private Map<Double, String> distanceAndPlaceMapForAllCities = new TreeMap<>();
    private HarvesineFormula harvesine = new HarvesineFormula();

public static ReadJsonFile getReadJson() {
    return readJson;
}


@SuppressWarnings("unchecked")
public void convertJsonToJavaObjects(String latitudeOfSearchedCity, String longitudeOfSearchedCity) throws IOException, JsonParseException {

    ObjectMapper om = new ObjectMapper();               
    om.configure(org.codehaus.jackson.map.DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); //ignore fields that are not formatted properly
    TypeReference<HashMap<Object,Object>> typeRef = new TypeReference<HashMap<Object,Object>>() {};
    HashMap<Object, Object> resultMap = om.readValue(new URL("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_month.geojson"), typeRef);

    ArrayList<Object> featuresArrayList = (ArrayList<Object>) resultMap.get("features");

    for(Object o : featuresArrayList) {
        try {
            LinkedHashMap<Object, Object> featuresLinkedHashMapInside = (LinkedHashMap<Object, Object>) o;
            Map<Object, Object> newMapping = (Map<Object, Object>) featuresLinkedHashMapInside.get("properties");
            place = newMapping.get("place").toString();
            Map<Object, Object> geometryMap = (Map<Object, Object>) featuresLinkedHashMapInside.get("geometry");
            ArrayList<Object> coordinatesArrayList = (ArrayList<Object>) geometryMap.get("coordinates");            
            longitude = (double) coordinatesArrayList.get(0);
            latitude = (double) coordinatesArrayList.get(1);

            double latitudeOfSearchedCityDouble = Double.parseDouble(latitudeOfSearchedCity);
            double longitudeOfSearchedCityDouble = Double.parseDouble(longitudeOfSearchedCity);

            double distanceBetweenTheCityAndEarthquakes = 
                    harvesine.haversine(latitudeOfSearchedCityDouble, longitudeOfSearchedCityDouble, latitude, longitude);

            distanceAndPlaceMapForAllCities.put(distanceBetweenTheCityAndEarthquakes, place);


        } catch (ClassCastException | NullPointerException e) {
            continue;
        }
    }           
}

public TreeMap<Double, String> read10closestCities() {
    TreeMap<Double, String> first10resultsFromTheList = distanceAndPlaceMapForAllCities.entrySet().stream()
            .limit(10)
            .collect(TreeMap::new, (m, e) -> m.put(e.getKey(), e.getValue()), Map::putAll);  
    return first10resultsFromTheList;
}
}

HarvesineFormula.java

public class HarvesineFormula {

public double haversine(double latitude1stCity, double longitude1stCity, 
        double latitude2ndCity, double longitude2ndCity) {

    double distanceBetweenLatitudes = Math.toRadians(latitude2ndCity - latitude1stCity);
    double distanceBetweenLongitudes = Math.toRadians(longitude2ndCity - longitude1stCity);
    latitude1stCity = Math.toRadians(latitude1stCity);
    latitude2ndCity = Math.toRadians(latitude2ndCity);
    double a = Math.pow(Math.sin(distanceBetweenLatitudes / 2), 2) + 
            Math.pow(Math.sin(distanceBetweenLongitudes / 2), 2) * 
            Math.cos(latitude1stCity) * Math.cos(latitude2ndCity);
    double radiusOfTheEarth = 6371;
    double c = 2 * Math.asin(Math.sqrt(a));
    return radiusOfTheEarth * c;
}
}

earthquakesList.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>

<html>
<head>
<%@ page isELIgnored="false" %>
<meta charset="UTF-8">
</head>
<body>


        <div>
            <form action="/read" method="post">
                <label>Latitude</label> 
                <fieldset>
                    <input type="text" 
                    name="latitudeOfSearchedCity" 
                    id="latitudeOfSearchedCity" 
                    class="form-control" 
                    oninvalid="this.setCustomValidity('Type in latitude in a format 00.000')"
                    onchange="try{setCustomValidity('')}catch(e){}"
                    oninput="setCustomValidity(' ')"
                    pattern="^[-]?(\d+|\d*\.\d+)$"
                    required="required" />
                </fieldset>

                <label>Longitude</label> 
                <fieldset>
                    <input type="text" 
                    name="longitudeOfSearchedCity" 
                    id="longitudeOfSearchedCity" 
                    class="form-control" 
                    oninvalid="this.setCustomValidity('Type in longitude in a format 00.000')"
                    onchange="try{setCustomValidity('')}catch(e){}"
                    oninput="setCustomValidity(' ')"            
                    pattern="^[-]?(\d+|\d*\.\d+)$" 
                    required="required" />
                </fieldset>

                <fieldset>
                <label>Select a city</label> 
                <select id="countrySelect">
                    <option>None</option>
                    <option value="35.084385_-106.650421">Albuquerque</option>                              
                    <option value="33.748997_-84.387985">Atlanta</option>
                    <option value="41.878113_-87.629799">Chicago</option>                           
                    <option value="32.776665_-96.796989">Dallas</option>
                    <option value="39.739235_-104.990250">Denver</option>   
                    <option value="31.761877_-106.485023">El Paso</option>                                                          
                    <option value="29.760427_-95.369804">Houston</option>                                                       
                    <option value="30.332184_-81.655647">Jacksonville</option>
                    <option value="39.099728_-94.578568">Kansas City</option>   
                    <option value="36.169941_-115.139832">Las Vegas</option>                                
                    <option value="34.052235_-118.243683">Los Angeles</option>                                                      
                    <option value="35.149532_-90.048981">Memphis</option>   
                    <option value="43.038902_-87.906471">Milwaukee</option>         
                    <option value="44.977753_-93.265015">Minneapolis</option>                                                       
                    <option value="29.951065_-90.071533">New Orleans</option>                                                                                   
                    <option value="40.712776_-74.005974">New York City</option>
                    <option value="28.538336_-81.379234">Orlando</option>                       
                    <option value="39.952583_-75.165222">Philadelphia</option>
                    <option value="33.448376_-112.074036">Phoenix</option>                              
                    <option value="40.440624_-79.995888">Pittsburgh</option>
                    <option value="45.512230_-122.658722">Portland</option>                                 
                    <option value="38.581573_-121.494400">Sacramento</option>                                   
                    <option value="29.424122_-98.493629">San Antonio</option>   
                    <option value="32.715736_-117.161087">San Diego</option>                                        
                    <option value="37.338207_-121.886330">San Jose</option>                                                                                                 
                    <option value="47.606209_-122.33206">Seattle</option>
                    <option value="38.627003_-90.199402">St. Louis</option> 
                    <option value="32.222607_-110.974709">Tucson</option>                           
                    <option value="38.907192_-77.036873">Washington D.C.</option>                                                                                           
                </select>
                </fieldset>

                <br />

                <button type="submit">Submit</button>
            </form>
        </div>

        <div class="resultsTable2">
            <table>
                <thead>
                    <tr>
                        <th>Distance</th>
                        <th>Location</th>

                    </tr>
                </thead>

                <tbody>
                    <c:forEach items="${outputMap}" var="entry">
                        <tr>
                            <td><fmt:formatNumber type="number" maxFractionDigits="1"
                                    value="${entry.key}" /> KM</td>
                            <td><c:out value="${entry.value}" /></td>
                        </tr>
                    </c:forEach>
                </tbody>
            </table>
        </div>


<script src="webjars/jquery/1.9.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<script>
$('#countrySelect').on('change', function () {
    var val = this.value;
    var parts = val.split("_");
    $('#latitudeOfSearchedCity').val(parts[0]);
    $('#longitudeOfSearchedCity').val(parts[1]);
});
</script>

</body>
</html>

web.xml

    <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
    http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1">

    <display-name>Archetype Created Web Application</display-name>
      <servlet>
      <servlet-name>PrintEarthquakesServlet</servlet-name>
      <servlet-class>com.dominikazb.earthquakes.servlets.PrintEarthquakesServlet</servlet-class>
      </servlet>
      <servlet>
      <servlet-name>ReadLongitudeAndLatitudeServlet</servlet-name>
        <servlet-class>com.dominikazb.earthquakes.servlets.ReadLongitudeAndLatitudeServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>PrintEarthquakesServlet</servlet-name>
        <url-pattern>/PrintEarthquakesServlet</url-pattern>
      </servlet-mapping>
      <servlet-mapping>
        <servlet-name>ReadLongitudeAndLatitudeServlet</servlet-name>
        <url-pattern>/ReadLongitudeAndLatitudeServlet</url-pattern>
      </servlet-mapping>

      <welcome-file-list>
        <welcome-file>earthquakesList.jsp</welcome-file>
      </welcome-file-list>
    </web-app>

pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dominikazb</groupId>
<artifactId>10closestEarthquakes</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>10closestEarthquakes Maven Webapp</name>
<url>http://maven.apache.org</url>

<properties>
    <tomcat.version>7.0.50</tomcat.version>
</properties>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>

    <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jstl</artifactId>
        <version>1.2</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.github.jsimone/webapp-runner -->
    <dependency>
        <groupId>com.github.jsimone</groupId>
        <artifactId>webapp-runner</artifactId>
        <version>9.0.27.1</version>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>bootstrap</artifactId>
        <version>3.3.6</version>
    </dependency>

    <dependency>
        <groupId>org.webjars</groupId>
        <artifactId>jquery</artifactId>
        <version>1.9.1</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.10</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.codehaus.jackson/jackson-mapper-asl -->
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.13</version>
    </dependency>
</dependencies>

<build>
    <finalName>10closestEarthquakes</finalName>

    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-eclipse-plugin</artifactId>
            <version>2.9</version>
            <configuration>
                <wtpversion>2.0</wtpversion>
                <wtpContextName>todo</wtpContextName>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.2</version>
            <configuration>
                <verbose>true</verbose>
                <source>1.8</source>
                <target>1.8</target>
                <showWarnings>true</showWarnings>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.tomcat.maven</groupId>
            <artifactId>tomcat7-maven-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <path>/</path>
                <contextReloadable>true</contextReloadable>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <failOnMissingWebXml>false</failOnMissingWebXml>
                <webappDirectory>${project.build.directory}/${project.artifactId}
                </webappDirectory>
                <warName>${project.artifactId}</warName>
            </configuration>
        </plugin>

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>copy</goal>
                    </goals>
                    <configuration>
                        <artifactItems>
                            <artifactItem>
                                <groupId>com.github.jsimone</groupId>
                                <artifactId>webapp-runner</artifactId>
                                <version>9.0.27.0</version>
                                <destFileName>webapp-runner.jar</destFileName>
                            </artifactItem>
                        </artifactItems>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>

</build>
</project>

完整代码可在here 获得。请帮忙??

【问题讨论】:

    标签: java json servlets


    【解决方案1】:

    主要的逻辑错误在这里:

    distanceAndPlaceMapForAllCities.put(distanceBetweenTheCityAndEarthquakes, place);
    

    因为地图会永远增长。

    将此行添加到您的方法中

    distanceAndPlaceMapForAllCities = new TreeMap<>();
    ObjectMapper om = new ObjectMapper();           
    ...
    

    你会得到正确的答案,因为每次调用方法都会“重置”地图。

    无论如何,我在您的代码中看到了一些其他“错误的想法”,例如

    • 使用似乎不是很有用的静态字段
    • 在 2 个不同的函数调用之间共享“位置”(在多线程环境中,您可能会遇到问题)

    无论如何我希望能帮助到你。

    【讨论】:

    • 谢谢!重置确实有帮助!您对如何省略创建这张永远增长的地图有什么建议吗?为了按距离对距离进行排序,我必须查看所有结果(地图似乎是最简单的方法)。对不起,静态字段,它是以前版本的剩余部分,我已经将它们删除,因为我不使用它们。感谢所有的 cmets,它们非常有用!
    • 你看过这个页面吗? [链接]earthquake.usgs.gov/fdsnws/event/1/)(https://… 有一个“查询”方法可以调用(带有许多查询参数),在我看来,响应与您当前对 all_month.geojson 的调用具有相同的形式
    • 抱歉link 中的错误,它会将您带到“API 文档 - 地震目录”
    • 不,我还没有看到这个页面,谢谢,我会调查一下!
    【解决方案2】:

    对于第一个问题,ReadJson 类及其使用方式存在一些问题。

    1. ReadJson 用作 Singleton,即此类只有一个实例,并且将在所有 HTTP 请求之间共享。
    2. 每个新的 HTTP 请求都将填充 ReadJson 类的 distanceAndPlaceMapForAllCities 成员。请注意,该成员将包含所有先前请求的数据。它也是一个按距离排序的 TreeMap,所以过一段时间你得到相同的结果也就不足为奇了。
    3. 每个 HTTP 请求都会通过网络获取 json 数据文件并进行解析。

    您应该重构 JSON 数据的处理。仅读取一次 JSON 文件(或每天一次以获取更新)。在计算distanceAndPlaceMapForAllCities 时,请确保为每个请求使用一个新实例。

    【讨论】:

    • 谢谢,这些都是我以前没有注意到的非常有用的内容!谢谢,我会全部应用! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 2019-12-10
    • 2011-10-02
    相关资源
    最近更新 更多