【问题标题】:How to reload a specfic part of a JSP with a new Model over AJAX (Spring MVC)?如何使用 AJAX (Spring MVC) 上的新模型重新加载 JSP 的特定部分?
【发布时间】:2017-07-03 22:12:06
【问题描述】:

我在用什么?

  • Tomcat 7.0.56
  • JAVA 1.8
  • Spring MVC
  • jQuery

目标是什么?

我正在实现一个内容目录。
例如,用户搜索特定的姓名或电话号码。然后在页面左侧显示联系人列表。在右侧应该显示被选中的联系人的详细信息。

问题出在哪里?

我的问题在于显示细节。

我的代码:

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html >
<%@ include file="includes/header.jsp" %>
<body>
    <div class="pageContainer container-fluid">
        <div class="row">
            <%@ include file="searchBar.jsp" %>
        </div>
        <div class="row">
            <div class="containerOverView col-lg-5 col-md-6 col-sm-12 col-xs-12">
                <%@ include file="overView.jsp" %>
            </div>
            <div class="containerDetailView col-lg-7 col-md-6 col-sm-12 col-xs-12">
                <%@ include file="detailView.jsp" %>
            </div>
        </div>
    </div>
</body>
</html>


detailView.jsp

<ul class="flex-container">
    <li class="flex-item-photo">Photo</li>
    <li class="flex-item-pdetails">Personal Details</li>
    <li class="flex-item-cdetails">Company Details</li>
    <li class="flex-item-map">Map:
        ${detailSearchResult.name}
    </li>

</ul>


MainController.java

// Delivers the refresh-information for the ajax request, when the detail view gets reloaded
    @RequestMapping(value = "/refreshDetail", method = RequestMethod.POST)
    @ResponseBody
    private String refreshDetailView(HttpServletRequest hsr, @RequestParam String id, ModelMap model){
        model.addAttribute("detailSearchResult", Dao.getDetailViewData(id));
        return "detailView";
    }


main.js

$(document).ready(function(){
$(".overViewListEmployee").click(function () {
    var id = $(this).find(".overViewEmployeeID").text();
    console.log("Works: " + id + ".");
    $.ajax({
        type: "POST",
        accepts: "text/plain",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        url: "/refreshDetail",
        data: ({"id" : id}),
        success: function(response) {
            $(".containerDetailView").html(response);
        }
    });
});
});



究竟是什么不起作用?

在我看来,ajax 请求并没有真正得到有效的响应。据我了解,ajax 接受各种响应,但不知何故,当我调试 JavaScript 时,它说响应有 Response Error: response is not defined

错误代码:

使用上面的代码:
400:加载资源失败:服务器响应状态为 400(错误请求)

当我在 ma​​in.js 中注释掉以下行时:

 //contentType: "application/json; charset=utf-8",

406:(不可接受)


什么有效? (由于调试)

当我调试代码时,我看到 id 的值正确地进入了控制器,并且函数 Dao.getDetailView(id) 也正常工作。所以这实际上只是响应的问题。

我还尝试了什么?

我不确定它是否可以这样工作,方法是返回一个带有 detailView.jsp 页面名称的字符串,因为我不知道 model 是否应该重新加载该页面 我添加的属性也随之而来,并在 index.jsp 中呈现(其中包含 detailView.jsp)。
所以我也试着把 Controller-Function 像这样:

// Delivers the refresh-information for the ajax request, when the detail view gets reloaded
    @RequestMapping(value = "/refreshDetail", method = RequestMethod.POST)        
    private ModelAndView refreshDetailView(@RequestParam String id, ModelMap model){
        model.addAttribute("detailSearchResult", Dao.getDetailViewData(id));
        return new ModelAndView("detailView");
    }

并从 ma​​in.js 中删除这一行:

accepts: "text/plain",


我也尝试过返回模型:

return new ModelAndView("detailView", model);



我不经常使用 JavaScript,所以这可能是一个非常愚蠢和明显的错误,但我似乎找不到它。我真的尝试了我能找到的所有东西,但看起来我被困在这里了。

对于这个案例,我非常感谢任何形式的帮助 :)


更新:

main.js

$(".overViewListEmployee").click(function () {
    var id = parseInt($(this).find(".overViewEmployeeID").text());
    console.log("Works: " + id + ".");
    $.ajax({
        type: "POST",
        accept:"text/html",
        //contentType: "application/json; charset=utf-8",
        dataType: "html",
        url: "/refreshDetail",
        data: ({"id": id}),
        success: function(response) {
            $(".containerDetailView").html(response);
        }
    });
});


MainController.java

// Delivers the refresh-information for the ajax request, when the detail view gets reloaded
    @RequestMapping(value = "/refreshDetail", method = RequestMethod.POST, produces = MediaType.TEXT_HTML_VALUE)
    @ResponseBody
    private ModelAndView refreshDetailView(HttpServletRequest hsr, @RequestBody IdObject id, ModelMap model){
        model.addAttribute("detailSearchResult", Dao.getDetailViewData(id.getId()));
        return new ModelAndView("detailView", model);
    }


IdObject.java

public class IdObject {
int id;

public int getId() {
    return id;
}

public void setId(int id) {
    this.id = id;
}
}


现在根本没有到达控制器 - 仍然出现 415 错误。


更新 2:

WebInit.java(之前)

@Configuration
public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer{

protected Class<?>[] getRootConfigClasses() {
    return new Class<?>[]{RootConfig.class};
}

protected Class<?>[] getServletConfigClasses() {
    return new Class<?>[]{WebConfig.class};
}

protected String[] getServletMappings() {
    return new String[]{"/"};
}
}

WebInit.java(之后)

@Configuration
public class WebInit implements WebApplicationInitializer{

@Override
public void onStartup(ServletContext container) {
    // Create the 'root' Spring application context
    AnnotationConfigWebApplicationContext rootContext =
            new AnnotationConfigWebApplicationContext();
    rootContext.register(WebConfig.class);

    // Manage the lifecycle of the root application context
    container.addListener(new ContextLoaderListener(rootContext));

    // Create the dispatcher servlet's Spring application context
    AnnotationConfigWebApplicationContext dispatcherContext =
            new AnnotationConfigWebApplicationContext();
    dispatcherContext.register(RootConfig.class);

    // Register and map the dispatcher servlet
    ServletRegistration.Dynamic dispatcher =
            container.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
    dispatcher.setLoadOnStartup(1);
    dispatcher.addMapping("/");
}
}

现在我不确定这是否是您的意思,但从我读到的@AnnotationDrivenConfigAnnotationConfigWebApplicationContext 相同。而且由于我是使用纯 Java 的配置来做的,所以我想这就是我要走的路。 但我仍然遇到同样的错误。

WebConfig.java

@Configuration
@EnableWebMvc
@ComponentScan("com.avectris.newtel")
public class WebConfig extends WebMvcConfigurerAdapter {

@Bean
public InternalResourceViewResolver resolver() {
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/view/");
    resolver.setSuffix(".jsp");
    return resolver;
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/resources/**").addResourceLocations("/resources/");
    registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    registry.addResourceHandler("/sass_compiled/**").addResourceLocations("/sass_compiled/");
    registry.addResourceHandler("/js/**").addResourceLocations("/js/");
}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
    final ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    converter.setObjectMapper(objectMapper);
    converters.add(converter);
    super.extendMessageConverters(converters);
}
}

【问题讨论】:

  • 在您返回 html 代码时,您的 ajax 请求中的数据类型属性应该是“html”。并返回一个 ModelAndView。如果你返回一个字符串,你需要删除@ResponseBody。
  • @alfcope - 感谢您的快速回复!我试过了。不幸的是,我仍然收到 400: Bad Request 错误。知道还有什么可能导致这种情况吗?
  • 将接受更改为 'accepts:{html: "text/html"}' 并将 "produces = MediaType.TEXT_HTML_VALUE" 包含到控制器的请求映射注释中。
  • @alfcope - 仍然得到同样的错误。当我调试 JS 时,它仍然抛出 Reference Error: response is not defined
  • 另外,您正在使用 RequesParam 在控制器上获取 id。当您发送 json 对象时,您需要使用 RequestBody 并使用具有 id 属性的对象。如果将 url 更改为“/refreshDetail?id="+id 之类的内容,则无需在控制器上进行任何更改,但需要从 ajax 对象中删除内容类型和数据。

标签: javascript ajax spring jsp model


【解决方案1】:

查看您的 ajax 请求,我认为您正在尝试发送一个 json 对象(但实际上您不是),然后您正在尝试使用 @RequestParam 而不是 @RequestBody 获取 id 的值。

如果您不想在 ajax 有效负载中发送 json 对象,那么您的内容类型是错误的。尝试这样的事情。 data 属性将被 jQuery 转换为查询字符串。

$(document).ready(function(){
  $(".overViewListEmployee").click(function () {
    var id = $(this).find(".overViewEmployeeID").text();
    console.log("Works: " + id + ".");
    $.ajax({
        type: "POST",
        headers: {
            "Accept" : "text/html",
            "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
        },
        url: "/refreshDetail",
        //you can get rid of data if you change your url to "/refreshDatil?id="+id
        data: {"id" : id},
        success: function(response) {
            $(".containerDetailView").html(response);
        }
    });
  });
});

如果你真的想发送一个 json 对象,正如我在我的 cmets 上所说的,你需要在控制器级别做一些更改。


编辑

好的,您现在正在混合两种可能的解决方案。使用当前的 ajax 对象,您发送的不是 json 对象,而是普通的 http 请求。当 ajax 请求发生时,您可以在浏览器中查看网络选项卡,您会看到类似 /refreshDetail?id=yourid 的请求,paylod 中没有 json 对象。

另一方面,您的控制器使用 @RequestBody 试图从有效负载中获取像 IdObject 这样的对象,但您并没有发出这样的请求。您的控制器应如下所示:

@RequestMapping(value = "/refreshDetail", method = RequestMethod.POST, produces = MediaType.TEXT_HTML_VALUE)
private ModelAndView refreshDetailView(HttpServletRequest hsr, @RequestParam int id, ModelMap model){
    model.addAttribute("detailSearchResult", Dao.getDetailViewData(id));
    return new ModelAndView("detailView", model);
}

同时从 ajax 对象的 data 属性中删除括号:

$(".overViewListEmployee").click(function () {
    var id = parseInt($(this).find(".overViewEmployeeID").text());
    console.log("Works: " + id + ".");
    $.ajax({
        type: "POST",
        accept:"text/html",
        //contentType: "application/json; charset=utf-8",
        dataType: "html",
        url: "/refreshDetail",
        data: {"id": id},
        success: function(response) {
            $(".containerDetailView").html(response);
        }
    });
});

如果您想发送 json 有效负载 如果您真正需要的是从 javascript 发送一个 json 对象,那么您需要更改您的 ajax 请求

$(".overViewListEmployee").click(function () {
    var id = parseInt($(this).find(".overViewEmployeeID").text());
    console.log("Works: " + id + ".");
    $.ajax({
        type: "POST",
        accept:"text/html",
        dataType: "html",
        contentType: "application/json",
        url: "/refreshDetail",
        data: JSON.stringify({"id": id}),
        success: function(response) {
            $(".containerDetailView").html(response);
        }
    });
});

使用 contentType jQuery 设置标头 Content-Type,告诉您的控制器请求带有 json 有效负载。然后,JSON.stringify 将带有要发送的信息的 javascript 对象转换为 json 字符串,jQuery 将使用它作为有效负载。

在后端,您的控制器现在应该使用@RequestBody,因为信息不在请求参数中,而是在 json 有效负载中。所以,它应该看起来像这样:

@RequestMapping(value = "/refreshDetail", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.TEXT_HTML_VALUE)
    private ModelAndView refreshDetailView(HttpServletRequest hsr, @RequestBody IdObject id, ModelMap model){
        model.addAttribute("detailSearchResult", Dao.getDetailViewData(id.getId()));
        return new ModelAndView("detailView", model);
    }

在这种情况下,请求映射中的消费者属性不是强制性的,因为您没有任何其他映射到相同的值/refreshDetail,但它使代码更易于阅读。

在任何这种情况下,您都不必在控制器上使用@ResponseBody,因为您正在发回一个视图。发回jsonxml等时会用到它。

【讨论】:

  • 感谢您的回答!在这里我得到 415 (Unsupported Media Type) - 即使我添加 dataType = "html" 对于您之前的评论:它只是在这种状态下到达控制器:header:{accepts:"text/html"}, //contentType: "application/json; charset=utf-8", dataType: "html", url: "/refreshDetail", data: ({"id": id}), 我真的不知道为什么。我还尝试使用仅具有属性“id”的对象来执行此操作,如下所示:link.
  • 415(不支持的媒体类型)表示内容类型或接受标头错误,具体取决于您的控制器消费和生产的内容。您可以在浏览器上查看请求。
  • 所以我尝试了一些东西,但似乎都没有。
    我不确定我是否理解正确,但由于请求中的类型是 xhr,您在contentType: 'application/x-www-form-urlencoded; charset=UTF-8' 之前的建议应该有效。这也是默认值,但这并没有改变任何东西。
    所以我在@RequestMapping 中使用produces = MediaType.APPLICATION_FORM_URLENCODED_VALUEheaders = "x-requested-with=XMLHttpRequest" 进行了尝试,但这也没有帮助。 (使用accepts:"text/html" & dataType:"html"
    仍然得到相同的错误:415 - xhr
  • 你不能使用那个产生的,它没有意义。您的控制器正在生成 html 内容。它必须是 MediaType.TEXT_HTML_VALUE,并且您的 ajax 对象必须接受该内容。尝试从标题中删除内容类型。
  • 好吧,这对我来说很有意义。如果我将其改回并删除contentType:"application/json ...,它将再次给我415(不支持的媒体类型)。如果我保留标题,目前没有任何区别。顺便说一句:如果我理解正确,我可以在header 内部或外部编写“accept”或“contentType”,对吗?
猜你喜欢
  • 2017-11-18
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
相关资源
最近更新 更多