如何通过AJAX(Spring MVC)上的新模型重新加载JSP的特定部分? [英] How to reload a specfic part of a JSP with a new Model over AJAX (Spring MVC)?

查看:97
本文介绍了如何通过AJAX(Spring MVC)上的新模型重新加载JSP的特定部分?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在用什么?

  • 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:未定义响应

错误代码:

使用上面的代码:
400:无法加载资源:服务器以400(错误请求)状态回应

当我在 main.js 中的以下行注释掉时:

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

406:(不可接受)


什么工作? (由于调试)

调试代码时,我看到id的值正确进入了Controller,并且功能Dao.getDetailView(id)也可以正常工作.因此,这实际上只是响应的问题.

我还尝试了什么?

我不确定是否能以这种方式工作,方法是返回一个带有 detailView.jsp 页面名称的字符串,该字符串应该重新加载,因为我不知道模型是否我要添加的属性也随它一起添加并呈现在 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");
    }

并从 main.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("/");
}
}

现在我不确定这是否是您的意思,但是从我读到的@AnnotationDrivenConfig与使用AnnotationConfigWebApplicationContext进行的操作相同.而且,由于我是使用纯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);
}
}

解决方案

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

如果您不想在ajax有效负载中发送json对象,则您的内容类型错误.尝试这样的事情.数据属性将由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对象(如我在评论中已经说过的那样),则需要在控制器级别进行一些更改.


修改

好,您现在正在混合两种可能的解决方案.对于当前的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);
    }

在这种情况下,请求映射上的consumers属性不是必需的,因为您没有其他映射到相同值的/refreshDetail,但是它使代码更易于阅读.

在任何一种情况下,您都不必在控制器上使用@ResponseBody,因为您要发回视图.当发回jsonxml

时,将使用它.

What am I using?

  • Tomcat 7.0.56
  • JAVA 1.8
  • Spring MVC
  • jQuery

What is the goal?

I'm implementing a content directory.
The user searches for a specific name or phone number for example. Then a list of contacts shows up on the left side of the page. On the right side there should details be displayed of a contact that gets selected.

Where is the problem?

My problem lays on the part of showing the details.

My Code:

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



What exactly doesn't work?

It seems to me, that the ajax request doesn't really get a valid response. From my understanding ajax accepts every kind of response but somehow, when I debug the JavaScript it says that the response has a Response Error: response is not defined

Error Codes:

With the code above:
400: Failed to load resource: the server responded with a status of 400 (Bad Request)

When I comment out following line in main.js:

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

406: (Not acceptable)


What does work? (due to debugging)

When I debugged the code I saw that the value of the id is getting into the Controller correctly and also the function Dao.getDetailView(id) works properly. So it's really just an issue of the response.

What else have I tried?

I'm not sure if it works that way, by returning a string with the name of the detailView.jsp page that should be reloaded since I don't know if the model I'm adding the attribute to is also going with it and rendered in the index.jsp (where detailView.jsp is included).
So I also tried to put the Controller-Function like this:

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

and removing this line from main.js:

accepts: "text/plain",


I also tried by returning the model as well:

return new ModelAndView("detailView", model);



I'm not working with JavaScript that often, so it's possibly a really silly and obvious mistake but I can't seem to find it. I literally tried out everything I could find but it looks like I'm stuck here.

I would really appreciate any kind of help on this case :)


Update:

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


Right now the Controller isn't reached at all - still got that 415 Error.


Update 2:

WebInit.java (before)

@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 (after)

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

Now I'm not sure if it's what you meant but from what I read @AnnotationDrivenConfig is the same as to do it with AnnotationConfigWebApplicationContext. And since I'm doing it with pure Java based Configuration I figured, that'd be my way to go. But I still got the same error though.

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

解决方案

Taking a look to your ajax request I think you are trying to send a json object (but you are not, really) and then your are trying to get the value for the id with @RequestParam instead of @RequestBody.

If you do not want to send a json object in the ajax payload, then your content-type is wrong. Try something like this. The data property is going to be is converted to a query string by 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);
        }
    });
  });
});

If you really want to send a json object, as I have already said on my comments, you need do some changes at your controller level.


Edit

Ok, you are now mixing the two possible solutions. With your current ajax object you are not sending a json object, but a normal http request. You can check the network tab at your browser when the ajax request happend and you will see a request like /refreshDetail?id=yourid, without json object in the paylod.

Your controller, on the other hand, using @RequestBody is trying to get an object like IdObject from the payload, but your are not doing a request like that. Your controller should looks like:

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

Also remove the brackets from the data property at your ajax object:

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

In case you want to send a json payload If what you really need is send a json object from javascript then you need to change your ajax request

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

With contentType jQuery is setting the header Content-Type, telling your controller the request is coming with a json payload. Then, JSON.stringify is converting the javascript object with the info to be send into a json string and it will be used by jQuery as payload.

On the backend side, your controller, now, should use @RequestBody because the info is not coming within the request parameters, but a json payload. So, it should looks like something to this:

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

The consumes property at the request mapping, in this case, is not mandatory, as you do not have any other mapping to the same value /refreshDetail, but it makes the code easier to read.

You do not have to use @ResponseBody at your controller, on any of this cases, because you are sending back a view. You will use it when sending back a json, xml, etc.

这篇关于如何通过AJAX(Spring MVC)上的新模型重新加载JSP的特定部分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆