Dynamic form and data binding with Spring MVC

后端 未结 2 1570
予麋鹿
予麋鹿 2021-02-04 08:44

In my Spring MVC application I need to implement a dynamic questionnaire form: I have N questions and for each I have 3 options.

So in my page I\'ll have something like

相关标签:
2条回答
  • 2021-02-04 09:22

    how to post data and handle ModelAttribute binding in this scenario

    you can do,

    i am considering Question class like:

    public class Question {
        private String question;
        private Map<Integer,Option> optionMap;
        private Integer selectedOptionKey;
            //getters and setters
    }
    

    and Option class like:

    public class Option {
    
        private Integer optionKey;
        private String optionText;
    
        //getters and setters
    }
    

    and one QuestionsModel class for form binding like:

    public class QuestionsModel {
        private Map<Integer, Question> questionMap;
        //getters and setters
    }
    

    and inside Controller class GET handler method, populate questions for example:

    @RequestMapping(method=RequestMethod.GET)
        public String index(Model model){                
        Option optionA = new Option(1, "A");
        Option optionB = new Option(2, "B");
        Option optionC = new Option(3, "C");
    
        Map<Integer, Option> optionMap = new HashMap<Integer, Option>();
        optionMap.put(optionA.getOptionKey(),optionA);
        optionMap.put(optionB.getOptionKey(),optionB);
        optionMap.put(optionC.getOptionKey(),optionC);
    
        Question question1 = new Question("A Q", optionMap, 1);
        Question question2 = new Question("B Q", optionMap, 1);
        Question question3 = new Question("C Q", optionMap, 1);
        Map<Integer, Question> questionMap = new HashMap<Integer, Question>();
        questionMap.put(1, question1);
        questionMap.put(2, question2);
        questionMap.put(3, question3);
    
        model.addAttribute("questionsModel", new QuestionsModel(questionMap));
    
        return "index";
    }
    

    finally in jsp page use <form:hidden.. to keep old values, and render form elements like:

    <c:url value="/questionPost" var="postUrl"/>
    
    <form:form action="${postUrl}" modelAttribute="questionsModel" method="post">
        <table>
        <tr>
            <th>Question</th>
            <th>Options</th>        
        </tr>   
        <c:forEach items="${questionsModel.questionMap}" var="currQue" varStatus="queIndex">
            <tr>
                <td>
                    <form:hidden path="questionMap[${queIndex.count}].question"/>
                    <label>Question:</label><c:out value="${currQue.value.question}"/><br/>
                </td>
                <td>
                <c:forEach items="${currQue.value.optionMap}" var="opt" varStatus="optionIndex">
                    <form:hidden path="questionMap[${queIndex.count}].optionMap[${optionIndex.count}].optionText"/>
                    <form:hidden path="questionMap[${queIndex.count}].optionMap[${optionIndex.count}].optionKey"/>
    
                    <form:radiobutton path="questionMap[${queIndex.count}].selectedOptionKey"
                        value="${opt.value.optionKey}" label="${opt.value.optionText}"/>
    
                </c:forEach>
    
                 </td>
            </tr>
        </c:forEach>
        </table>
        <input type="submit"/>
    </form:form>
    

    you can receive binding and model in POST like:

    @RequestMapping(value="/questionPost", method=RequestMethod.POST)
    public String indexPost(@ModelAttribute("questionsModel") QuestionsModel questionModel, BindingResult result){
        System.out.println(questionModel.getQuestionMap());
    
        return "redirect:/";
    } 
    
    0 讨论(0)
  • 2021-02-04 09:25

    This class is my model attribute:

    public class Questionnaire {
        private List<Question> questions = new ArrayList<>();
        private List<Answer> answers = new ArrayList<>();
    
        // set + get
    }
    

    And:

    public class Question {
        private int id;
        private String text;
    
        // set+ get
    
    }
    
    public class Answer {
        private int questionId;
        private int value;
    
        // set + get
    }
    

    I populate questions list before I put it into model.

    In my page I use this code:

    <c:forEach items="${questionnaire.questions}" var="question"
        varStatus="gridRow">
        <div>
        ${question.text} 
            <s:bind path="questionnaire.answers[${gridRow.index}].questionID">
                <input type="hidden" name="${status.expression}"
                    id="${status.expression}" value="${question.id}" />
            </s:bind>
            <s:bind path="questionnaire.answers[${gridRow.index}].value">
                <sf:radiobuttons path="${status.expression}"
                    items="${radio_button_options}" />
            </s:bind>
        </div>
    </c:forEach>
    

    Posting this form I get a fully populated questionnaire instance in my controller.

    NOTE I found this post very helpful to solve my problem.

    0 讨论(0)
提交回复
热议问题