求教Spring mvc 处理 ajax问题,在线等
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求教Spring mvc 处理 ajax问题,在线等相关的知识,希望对你有一定的参考价值。
参考技术A Spring mvc 3.x版本,在支持Ajax方面还是不错的,看文档我们发现,只要我们在Controller里添加@RequestBody 和@ResponseBody两个标签后,就能把前台传过来的JSON对象进行转换成我们的java对象,也能将spring mvc里面的model直接返回回Ajax请求,转换器会自动的帮我们将java对象转换成JSON对象。需要的jar包 : jackson-mapper-asl-1.8.4.jar
jackson-core-asl-1.8.5.jar
这是DispatcherServlet的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置这个component-scan 的时候,会隐式的配置了下面2个bean
AutowiredAnnotationBeanPostProcessor :用于@Autowired标签为field注入依赖。
CommonAnnotationBeanPostProcessor
-->
<context:component-scan base-package="com.line.web.*"/>
<!-- 配置注解式的Handler
spring 3.1之前使用的是下面两个
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
spring 3.1之后默认注入的是
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
-->
<!-- 默认配置注解式的Handler-->
<mvc:annotation-driven/>
<!-- 配置视图处理器,用于处理controller返回的视图 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="WEB-INF/view/"/>
<property name="suffix" value=".jsp"/>
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
</bean>
<!-- 配置静态文件处理器 -->
<mvc:resources location="/public/img/" mapping="public/img/**"/>
<mvc:resources location="/public/js/" mapping="public/js/**"/>
<mvc:resources location="/public/css/" mapping="public/css/**"/>
<mvc:resources location="/public/file/" mapping="public/file/**"/>
</beans>
想要让我们的项目支持JSON数据的话,必须做一些配置
//spring 3.1之前的需要这样配置
//方案一
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" p:supportedMediaTypes="*/*" />
</mvc:message-converters>
</mvc:annotation-driven>
//方案二 显式的定义messageConverters
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>
//spring 3.1之后的版本
//方案一
<mvc:annotation-driven/>
//方案二
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" p:ignoreDefaultModelOnRedirect="true" >
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
配置好后,我们的Controller只要这样配置就星了
package com.line.web.controller;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import com.line.web.model.User;
import com.line.web.service.UserService;
@Controller
@RequestMapping("/user")
public class UserManagerController
@Autowired
private UserService userService;
@RequestMapping(value="/login",method=RequestMethod.POST)
public @ResponseBody ModelMap login(@RequestBody User a,ModelMap model)
String account = a.getAccount();
String password = a.getPassword();
System.out.println("account: " + account);
System.out.println("password: " + password);
if( !userService.checkFormat(account, password))
model.addAttribute("errorMsg","账号和密码不能为空,且不带特殊字符");
return model;
User user = userService.verification(account, password);
if(user != null)
model.addAttribute("user",user);
model.addAttribute("userId",user.getId());
else
model.addAttribute("errorMsg","账户不存在或密码错误!");
return model;
class User
private String account;
private String password;
public String getAccount()
return account;
public String getPassword()
return password;
public void setPassword(String password)
this.password = password;
public void setPassword(String account)
this.account = account;
页面的ajax只要向下面写就行
$.ajax(
url: "user/login",
type:"POST",
cache:false,
headers:
'Content-Type':'application/json',
'Accept':'application/json'
,
dataType:"json",
/* 有问题的版本
data:
'account' : $("#lg-account").val(),
'password' : $("#lg-psw").val()
,
*/
data: JSON.stringify(
'account' : $("#lg-account").val(),
'password' : $("#lg-psw").val()
),
error: function(),
success: function(data)
);
这里再说一下在配置中可能出现的错误,比如406和415,分别是“无法接受”以及“不支持媒体类型”,看到这里大家都可能猜到可能是json的问题,我们首要排除的是,我们的jar包引进来了没有,因为这个和json的转换息息相关,这部分没有问题后,前面Ajax代码注释里有提到一个有问题的版本,本来查了一下JQuery它的ajax函数里的data只接受spring或者plainObject ,这里的plainObject在经过spring 转换器转换的时候就有问题了,所以我们必须要先将我们的JSON序列化了,也就是JSON.stringify()这个方法。如果到这里还有406的问题,那么看一下你的http请求头里面Content-Type是application/json,记得在Ajax里设置好请求头。基本到现在就可以了。
处理 Thymeleaf Spring MVC AJAX 表单及其错误消息的推荐方法
【中文标题】处理 Thymeleaf Spring MVC AJAX 表单及其错误消息的推荐方法【英文标题】:Recommended way to handle Thymeleaf Spring MVC AJAX Forms and their error messages 【发布时间】:2015-11-18 16:56:23 【问题描述】:在 Thymeleaf 方面处理 AJAX 表单及其错误消息的推荐方法是什么?
我目前有一个 Spring 控制器,它返回字段的 JSON 概览及其各自的错误消息,但不得不求助于完全手写的 JQuery(或只是普通的 Javascript)感觉有点不对劲,而且速度很慢;特别是因为我打算在应用程序中使用大量表格。
【问题讨论】:
没有正确、错误或推荐的方法来做到这一点。这实际上取决于您的应用程序的设置方式、您的 MVC 层以及您想要显示的内容。您的选项包括警报、片段、分组消息等。我使用多种方法,具体取决于我想要返回给用户的内容和格式。 嗯,我主要是在寻找最快的方法。拉德和所有。所以我可以快速为我的后端构建一个好看的前端,这需要更多的工程。 再次,这真的取决于您的设置方式。对于我使用片段的表单,这样一切都是标准化的。对于单数输入/选择,我使用 javascript 对象来隐藏/显示错误。 你有这方面的一些例子吗,Aeseir?这将是我的问题的答案。 【参考方案1】:不知道是否还有人感兴趣,但我将把它留在这里,以供任何人寻找示例解决方案。
我实现了 yorgo 的解决方案,并通过在片段中包含脚本来解决“缺陷”。还有一个小缺陷,如果有多个带有额外参数的提交按钮(通常用于在 spring + thymeleaf 中实现动态表单),则在序列化表单时信息会丢失。我通过手动将此信息附加到序列化表单中解决了这个问题。
您可以在此处查看我对 yorgo 解决方案的实施以及修复:https://github.com/Yepadee/spring-ajax/blob/master/src/main/resources/templates/new_project.html
它的好处在于,您只需执行以下操作即可在任何现有的 thymeleaf 表单上实现它:
-
将脚本放入表单并使其引用表单的id
将表单放入片段中
更改控制器中的 post 方法以返回表单片段而不是整个模板
【讨论】:
【参考方案2】:不确定是否可以将其视为最佳做法,但这是我所做的:
Map<String, String> errorMap = binding.getFieldErrors()
.stream().collect(Collectors.toMap(
e -> e.getField(), e -> messageSource.getMessage(e, locale)));
然后我将地图发送回 ajax 响应以在“成功”部分进行处理。
【讨论】:
【参考方案3】:我喜欢做的是在发生错误时替换整个表单。下面是一个超级原始的例子。我不会使用大量片段来呈现表单……只是保持简单。
这是用 Spring 4.2.1 和 Thymeleaf 2.1.4 编写的
代表用户信息表单的基本类:UserInfo.java
package myapp.forms;
import org.hibernate.validator.constraints.Email;
import javax.validation.constraints.Size;
import lombok.Data;
@Data
public class UserInfo
@Email
private String email;
@Size(min = 1, message = "First name cannot be blank")
private String firstName;
控制器:UsersAjaxController.java
import myapp.forms.UserInfo;
import myapp.services.UserServices;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.transaction.Transactional;
@Controller
@Transactional
@RequestMapping("/async/users")
public class UsersAjaxController
@Autowired
private UserServices userServices;
@RequestMapping(value = "/saveUserInfo", method = RequestMethod.POST)
public String saveUserInfo(@Valid @ModelAttribute("userInfo") UserInfo userInfo,
BindingResult result,
Model model)
// if any errors, re-render the user info edit form
if (result.hasErrors())
return "fragments/user :: info-form";
// let the service layer handle the saving of the validated form fields
userServices.saveUserInfo(userInfo);
return "fragments/user :: info-success";
用于呈现表单和成功消息的文件:fragments/user.html
<div th:fragment="info-form" xmlns:th="http://www.thymeleaf.org" th:remove="tag">
<form id="userInfo" name="userInfo" th:action="@/async/users/saveUserInfo" th:object="$userInfo" method="post">
<div th:classappend="$#fields.hasErrors('firstName')?has-error">
<label class="control-label">First Name</label>
<input th:field="*firstName" type="text" />
</div>
<div th:classappend="$#fields.hasErrors('first')?has-error">
<label class="control-label">Email</label>
<input th:field="*email" ftype="text" />
</div>
<input type="submit" value="Save" />
</form>
</div>
<div th:fragment="info-success" xmlns:th="http://www.thymeleaf.org" th:remove="tag">
<p>Form successfully submitted</p>
</div>
JS 代码将简单地将表单提交到表单操作属性中提供的 URL。当响应返回到 JS 回调时,检查是否有任何错误。如果有错误,请将表单替换为响应中的表单。
(function($)
var $form = $('#userInfo');
$form.on('submit', function(e)
e.preventDefault();
$.ajax(
url: $form.attr('action'),
type: 'post',
data: $form.serialize(),
success: function(response)
// if the response contains any errors, replace the form
if ($(response).find('.has-error').length)
$form.replaceWith(response);
else
// in this case we can actually replace the form
// with the response as well, unless we want to
// show the success message a different way
);
)
(jQuery));
同样,这只是一个基本示例。正如上面的 cmets 所述,没有正确或错误的方法可以解决这个问题。这也不完全是我的首选解决方案,我肯定会对此进行一些调整,但总体思路就在那里。
注意:我的 JS 代码也存在缺陷。如果您将表单替换为响应中的表单,则表单提交处理程序将不会应用于新替换的表单。如果走这条路线,您需要确保在替换表单后正确地重新初始化表单处理程序。
【讨论】:
【参考方案4】:这方面的文档很少,但如果您已经熟悉 Web Flow,则可能不需要更多。我不确定这种技术如何与 Thymeleaf 中的普通 bean 绑定一起工作。我很想看到一个完整的宠物诊所演示应用程序使用它,这样我就可以看到控制器。
docs
【讨论】:
以上是关于求教Spring mvc 处理 ajax问题,在线等的主要内容,如果未能解决你的问题,请参考以下文章
处理 Thymeleaf Spring MVC AJAX 表单及其错误消息的推荐方法
使用 Spring MVC 4 处理跨域预检 AJAX OPTIONS 请求