jaredr jaredr - 22 days ago 8
Javascript Question

Getting large form to Spring controller

I have a form whose purpose is to allow a user to create a new entry in a database table. The form is very large, ~50 fields in total. I'm needing a way get all of these values to my controller, though I don't see an easy way. Every solution I've seen is to have a

@RequestParam('field')
, but with around 50 fields that is a little crazy. Maybe if using a
@RequestParam Map<T, T>
is possible?

What I tried at first was to create an AJAX POST call to

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


but then the servlet complained about not finding the
add.jsp
file. This is sort of reasonable because that file does not exist, but I created a controller mapping
@RequestMapping(value="/add")
so I shouldn't actually need that file. I have another method which creates an AJAX GET call to
/search
with some url parameters, and that works fine. There is also no
search.jsp
file.

This problem is hard to explain, I hope I did a halfway decent job. Let's look at some code now, with omissions because dealing with ~50 form fields is very lengthy.

Starting with the JavaScript, which initiates this whole process:

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


So the flow of this is as follows: The user clicks on the
addNewRecordBtn
button, which fires the first function. This function grabs the value of every field in the form, then builds a URL with parameters for each of these values. The
addCase()
function is then called, which creates an AJAX POST (not sure what to call this?) to the URL that was just built. This function does not succeed, the error alerts provide zero information, but the server console claims
Failed to find resource /WEB-INF/views/add.jsp


Now we move into the controller.

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


The
caseManager.addNewSpecialClaimsCase(newCase)
call just creates a DTO object out of this model object, and then adds that new object to the database via some Hibernate magic. I don't know much about that side, other than it works.

So, I'm not sure if I'm going about this the right way. I hear there's a way to map a model object to a JSP form using Spring's tag library, but that would require a ton of rewriting as the form is huge. I'm also using Bootstrap to build the interface, and I'm not sure if Bootstrap and Spring's tag library mix well. I can't imagine why not.

I'm not sure if I need to be using AJAX here or not. I went with it because I don't want the page to have to reload or anything. I'm not usually a web developer, so I am sure I am lacking some fundamental knowledge here.

My main question is: given my sitatuation, what is the best way to get this massive form of information into my controller?

Thanks in advance for reading this wall of text and code and for any assistance you can offer!

Answer Source

Create a domain class that has all of these needed fields and generate getters and setters and also a constructor. Once you get all these fields/some of these fields POST as json to your controller. The appropriate controller will then call the required service and then the DAO will handle the persistence part. In short, send the data you need as a JSON object. The json will be made as java object and the operation on the same will be performed.

Here is the controller

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

}

}`

the @RequestBody annotation helps you to make the json object into java object.

with this, you can take the payload as json, and get the java object and send the json back to the UI with ResponseEntity<Class> annotation