【问题标题】:Getting large form to Spring controller获取大型表单到 Spring 控制器
【发布时间】:2014-07-30 16:35:38
【问题描述】:

我有一个表单,其目的是允许用户在数据库表中创建一个新条目。表格非常大,总共约 50 个字段。我需要一种将所有这些值传递给我的控制器的方法,尽管我没有看到一个简单的方法。我见过的每个解决方案都是有一个@RequestParam('field'),但有大约 50 个字段,这有点疯狂。也许可以使用@RequestParam Map<T, T>?

我最初尝试的是创建一个 AJAX POST 调用

baseapplication.com/add?field1=value1&field2=value2&...&field50=value50

但随后 servlet 抱怨找不到 add.jsp 文件。这是合理的,因为该文件不存在,但我创建了一个控制器映射@RequestMapping(value="/add"),所以我实际上不需要该文件。我有另一种方法,它使用一些 url 参数创建对 /search 的 AJAX GET 调用,并且效果很好。也没有search.jsp 文件。

这个问题很难解释,我希望我做得不错。现在让我们看一些代码,因为处理大约 50 个表单字段非常冗长,所以有一些遗漏。

从启动整个过程的 JavaScript 开始:

ctx = "baseapplication.com"
$('#addNewRecordBtn').on('click', function(){
    var m_insId = document.getElementById('m_insId');
    //This repeats for every field
    var url = ctx + '/add?insuredId=' + m_insId /** + all other fields **/;
    addCase(url);
});

function addCase(url) {
    $.ajax({
        url: url,
        type: 'POST'
    }).success(function(data){
        alert("Successfully added row");
    }).fail(function(jzXHR, textStatus, errorThrown){
        alert(jzXHR);
        alert(textStatus);
        alert(errorThrown);
    });
}

所以这个流程如下:用户点击addNewRecordBtn按钮,触发第一个函数。此函数获取表单中每个字段的值,然后为每个值构建一个带有参数的 URL。然后调用addCase() 函数,该函数创建一个AJAX POST(不确定如何调用它?)到刚刚构建的URL。此函数不成功,错误警报提供零信息,但服务器控制台声称Failed to find resource /WEB-INF/views/add.jsp

现在我们进入控制器。

@Controller
public class ApplicationController {

    @Autowired
    SpecialClaimsCaseManager caseManager;

    @RequestMapping(value="/add")
    public void addRow(@RequestParam Map<String, String> requestParams) {
        SpecialClaimsCase newCase = new SpecialClaimsCase();

        newCase.setInsuredId(requestParams.get("insuredId"));
        //Repeat this for all parameters

        caseManager.addNewSpecialClaimsCase(newCase);
}

caseManager.addNewSpecialClaimsCase(newCase) 调用只是从这个模型对象中创建一个 DTO 对象,然后通过一些 Hibernate 魔法将该新对象添加到数据库中。我对那方面了解不多,除了它有效。

所以,我不确定我是否以正确的方式处理这件事。我听说有一种方法可以使用 Spring 的标记库将模型对象映射到 JSP 表单,但是由于表单很大,因此需要大量重写。我也在使用 Bootstrap 来构建界面,我不确定 Bootstrap 和 Spring 的标签库是否混合得很好。我无法想象为什么不。

我不确定我是否需要在这里使用 AJAX。我选择了它,因为我不希望页面必须重新加载或任何东西。我通常不是网络开发人员,所以我确定我在这里缺乏一些基础知识。

我的主要问题是:鉴于我的情况,将这种大量信息输入控制器的最佳方式是什么?

提前感谢您阅读这堵文字和代码墙以及您可以提供的任何帮助!

【问题讨论】:

  • 您是否考虑过在 POST 正文中将所有内容作为 JSON/XML 有效负载发送?而不是名称值对?
  • 为这 50 个字段设置一个 POJO,将其视为命令对象,并通过 Ajax 调用 Spring Controller 序列化并发布该 POJO。
  • 这可能是一个愚蠢的问题,但您是否尝试在 addRow 方法中设置断点以查看它是否被命中?此外,如果您使用 jQuery(尽管我不建议您必须这样做),您可以使用它可用的序列化函数,这样您就不必抓取每个单独的字段。如果您不介意使用 jQuery,请查看此链接。 api.jquery.com/serialize
  • 你可以只使用模型属性并包装你需要的所有值吗?您也可以在其中放置地图、列表等。
  • 说真的!您可以创建一个模型(一个 Java 实体,其字段与您的表单中的字段相同)...... Spring MVC 将为您映射这些。你甚至可以进行花哨的验证。

标签: java javascript spring jsp spring-mvc


【解决方案1】:

创建一个包含所有这些必需字段的域类,并生成 getter 和 setter 以及构造函数。一旦您将所有这些字段/其中一些字段作为 json 发布到您的控制器。然后适当的控制器将调用所需的服务,然后 DAO 将处理持久性部分。 简而言之,将您需要的数据作为 JSON 对象发送。 json 将作为 java 对象进行操作。

这里是控制器

@Controller
@RequestMapping(value = "/students/association")
public class StudentDepartmentController {

@Autowired
private StudentService studentService;

@Autowired
private StudentDepartmentService studentDepartmentService;

@RequestMapping(value = "/add-department", method = RequestMethod.POST)
public ResponseEntity<StudentDepartment> createStudentDepartmentAssociation(
        @RequestBody final StudentDepartment studentDepartment) {

    StudentDepartment newStudentDepartment;

    // check if the student exists

    Student student = studentService.getStudentByUuid(studentDepartment
            .getStudentUuid().getUuid());

    if (null == student) {

        throw new IllegalArgumentException("No students found!");

    }

    // check the status of student
    if (student.getStatus() == Liveliness.INACTIVE) {
        throw new IllegalArgumentException(
                "cannot create an association with an inactive student! activate student first");
    }

    // check for valid department

    if (null == studentDepartment.getDepartment().getName()) {
        throw new IllegalArgumentException("No such Department");
    }

    // check if the association already exists

    if (null != findOneAssociationAgainstStudent(student)) {
        throw new IllegalArgumentException(
                "cannot create student department association, as "
                        + student.getUsn()
                        + " already present in another association ( "
                        + studentDepartment.getDepartment().getName()
                        + " )");
    }

    try {

        newStudentDepartment = studentDepartmentService
                .createNewAssociation(studentDepartment);

    } catch (DataIntegrityViolationException ex) {

        throw new AutomationTransactionException(
                "cannot create student department association, as "
                        + student.getUsn()
                        + " already present in another association ( "
                        + studentDepartment.getDepartment().getName()
                        + " )", ex);

    }

    return new ResponseEntity<StudentDepartment>(newStudentDepartment,
            HttpStatus.CREATED);
}

private StudentDepartment findOneAssociationAgainstStudent(Student student) {

    return studentDepartmentService.findOneAssociation(student);
}

private StudentDepartment findOne(Uuid uuid) {

    String studentDepartmentUuid = uuid.getUuid();

    return findOne(studentDepartmentUuid);

}

private StudentDepartment findOne(String uuid) {

    return studentDepartmentService.findOne(uuid);

}

@RequestMapping(value = "/delete-association", method = RequestMethod.DELETE)
public ResponseEntity<String> deleteStudentDepartmentAssociationByUuid(
        @RequestBody final StudentDepartment studentDepartment) {

    // check if association exists
    StudentDepartment association = findOne(studentDepartment.getUuid());
    if (null == association) {
        throw new IllegalArgumentException("No such association found!");
    }

    studentDepartmentService.deleteAssociation(association);

    return new ResponseEntity<String>("success", HttpStatus.OK);

}

}`

@RequestBody注解帮助你将json对象变成java对象。

通过这个,你可以将payload作为json,并获取java对象并使用ResponseEntity&lt;Class&gt;注解将json发送回UI

【讨论】:

  • 我已经有了域类。字段的名称是否需要与 JSP 表单中的名称相同?构造函数是否需要做任何事情,或者 setter 会起作用吗?控制器应该如何更改才能访问 JSON?
  • 听起来有人试图窃取我的积分。但是,是的……您需要将 .java 文件中的属性命名为与 HTML 表单元素中列出的属性相同。此外,您需要将域类的类名称作为端点方法签名的一部分。
  • 我将编辑我的答案,以便您可以看到这些操作...我已经为我需要在学生和部门域模型上执行的操作完成此操作...请尝试映射那些满足您的要求。
  • 此外,spring 的 DI 部分将自行设置所需的属性。您不必显式调用设置器。一旦你拥有了对象,并且想要保存这些值,就可以像对待任何其他 spring 管理的对象一样正常地进行操作。它会工作得很好:)
  • 您可能希望使用 @RestController 注释控制器,以将 @ResponseBody 功能隐式添加到处理程序。
猜你喜欢
  • 2017-11-01
  • 1970-01-01
  • 2018-06-20
  • 2017-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-21
  • 1970-01-01
相关资源
最近更新 更多