【问题标题】:Spring MVC @ModelAttribute returns "Bad Request" error 400Spring MVC @ModelAttribute 返回“错误请求”错误 400
【发布时间】:2018-02-09 10:51:04
【问题描述】:

尊敬的 Spring java 专业人士, 我的问题: 我正在尝试发送 POST 请求,但收到“错误请求 400”错误。 我在这里发现了一个类似的问题:Spring MVC @ModelAttribute method returns "Bad request" 400,但解决方案对我没有帮助。

也许你们中的某个人可以帮助我。

这是我的 MainControler.java 的一部分

@Controller
public class OverviewController {

    private static final Logger logger = Logger
        .getLogger(OverviewController.class);

    public OverviewController() {
        System.out.println("ExperimentController()");
    }

    @Autowired
    private ExperimentService experimentService;

    @Autowired
    private TestService testservice;    

    @RequestMapping(value = "/Testbereich/Versuch/Test")
    public ModelAndView newExperimentTest(ModelAndView model, @ModelAttribute("experiment") Experiment experiment) throws IOException{
         Test test = new Test();
         model.addObject("test", test);
         model.addObject("experiment", experiment);
         model.setViewName("TestView");
         return model;
    }

    @RequestMapping(value = "/Testbereich/Versuch/saveTest", method = RequestMethod.POST)
    public ModelAndView saveTest(@ModelAttribute("test") Test test) {

         testservice.addTest(test);
         return new ModelAndView("redirect:/Uebersicht/Experiment");
    }
}

还有我的实验.java 和 test.java 实体

@Entity
@Table(name = "Experiment")
public class Experiment implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 3291761748164983832L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int experiment_id;

    @Column
    private String reader_type;

    @Column
    private String antenne_A;

    @Column
    private String antenne_B;

    @Column
    private String antenne_C;

    @Column
    private String antenne_D;

    @Column
    private String antenne_E;

    @Column
    private String antenne_F;

    @Column
    private String antenne_G;

    @Column
    private String antenne_H;

    @Column
    private String antenne_I;


    @Column
    private String fill_hight;

    @Column
    private int angle;

    @Column
    private String additional;

    @OneToMany(mappedBy="experiment")
    private Set<Test> tests;

    public int getExperiment_id() {
        return experiment_id;
    }

    public void setExperiment_id(int experiment_id) {
        this.experiment_id = experiment_id;
    }

    public String getReader_type() {
        return reader_type;
    }

    public void setReader_type(String reader_type) {
        this.reader_type = reader_type;
    }

    public String getFill_hight() {
        return fill_hight;
    }

    public void setFill_hight(String fill_hight) {
        this.fill_hight = fill_hight;
    }

    public int getAngle() {
        return angle;
    }

    public void setAngle(int angle) {
        this.angle = angle;
    }

    public String getAdditional() {
        return additional;
    }

    public void setAdditional(String additional) {
        this.additional = additional;
    }

    public Set<Test> getTests() {
        return tests;
    }

    public void setTests(Set<Test> tests) {
        this.tests = tests;
    }

    public String getAntenne_A() {
        return antenne_A;
    }

    public void setAntenne_A(String antenne_A) {
        this.antenne_A = antenne_A;
    }

    public String getAntenne_B() {
        return antenne_B;
    }

    public void setAntenne_B(String antenne_B) {
        this.antenne_B = antenne_B;
    }

    public String getAntenne_C() {
        return antenne_C;
    }

    public void setAntenne_C(String antenne_C) {
        this.antenne_C = antenne_C;
    }

    public String getAntenne_D() {
        return antenne_D;
    }

    public void setAntenne_D(String antenne_D) {
        this.antenne_D = antenne_D;
    }

    public String getAntenne_E() {
        return antenne_E;
    }

    public void setAntenne_E(String antenne_E) {
        this.antenne_E = antenne_E;
    }

    public String getAntenne_F() {
        return antenne_F;
    }

    public void setAntenne_F(String antenne_F) {
        this.antenne_F = antenne_F;
    }

    public String getAntenne_G() {
        return antenne_G;
    }

    public void setAntenne_G(String antenne_G) {
        this.antenne_G = antenne_G;
    }

    public String getAntenne_H() {
        return antenne_H;
    }

    public void setAntenne_H(String antenne_H) {
        this.antenne_H = antenne_H;
    }

    public String getAntenne_I() {
        return antenne_I;
    }

    public void setAntenne_I(String antenne_I) {
        this.antenne_I = antenne_I;
    }

}

测试实体

@Entity
public class Test implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -2345940545223928492L;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private int test_id;

    @Column
    private int uid_count;

    @Column
    private int speed;

    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date test_stop;

    @Column
    @Temporal(TemporalType.TIMESTAMP)
    private Date test_start;

    @ManyToOne
    @JoinColumn(name="experiment_id", nullable=false)
    private Experiment experiment;


    public int getTest_id() {
        return test_id;
    }

    public void setTest_id(int test_id) {
        this.test_id = test_id;
    }

    public int getUid_count() {
        return uid_count;
    }

    public void setUid_count(int uid_count) {
        this.uid_count = uid_count;
    }

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        this.speed = speed;
    }

    public Date getTest_stop() {
        return test_stop;
    }

    public void setTest_stop(Date test_stop) {
        this.test_stop = test_stop;
    }

    public Date getTest_start() {
        return test_start;
    }

    public void setTest_start(Date test_start) {
        this.test_start = test_start;
    }

    public Experiment getExperiment() {
        return experiment;
    }

    public void setExperiment(Experiment experiment) {
        this.experiment = experiment;
    }

}

以及我的 TestView.jsp 的相关部分

    <form:form method="POST" action="saveTest" modelAttribute="test">
    <div class="container">

        <br>
        <br>

        <div class="row">
            <div class="col-lg-12">
                <div class="page-header">
                    <h1>Testbereich</h1>
                    <p class="lead">Erstellen sie ein neuen Test</p>
                </div>
            </div>
        </div>

        <br>
        <br>

        <div class="row">
            <div class="col-lg-5">

                <form:hidden path="test_id"/>
                <form:hidden path="experiment" value="${experiment}"/>

                <div class="form-group">
                    <div class="row">
                        <div class="col-3">
                            <input  type="button" class="btn btn-primary" id="input-start" value="Test Starten" onclick="clickStartButton()">
                        </div>
                        <div class="col-8 offset-1">
                            <form:input class="form-control" path="test_start" id="start_value" value="" disabled="true"></form:input>                              
                        </div>
                    </div>  
                </div>

                <div class="form-group">
                    <div class="row">
                        <div class="col-3">
                            <input  type="button" class="btn btn-primary" id="input-stop" value="Test Stoppen" onclick="clickStopButton()"></input>
                        </div>
                        <div class="col-8 offset-1">
                            <form:input class="form-control" path="test_stop" id="stop_value" value="" disabled="true"></form:input>
                        </div>

                    </div>  
                </div>

                <div class="form-group">
                    <label for="input-uidCount">Anzahl der erfassten UIDs</label>
                    <form:input class="form-control" path="uid_count" id="input-uidCount"/>
                </div>

                <div class="form-group">
                    <label for="input-speed">Geschwindigkeit des Testfahrzeugs in km/h</label>
                    <form:input class="form-control" path="speed" id="input-speed"/>
                </div>

                <div class="form-group">
                    <input type="submit" class="btn btn-primary" value="Test Speichern"/>
                </div>
            </div>         
        </div>
        <div class="col-lg-5 offset-lg-1">

        </div>
    </div>
</form:form>

<script type="text/javascript">

    function clickStartButton() {
        var datetime
        datetime = new Date().toISOString().slice(0, 19).replace('T', ' ');
        document.getElementById("start_value").value = datetime;
    }

    function clickStopButton() {
        var datetime
        datetime = new Date().toISOString().slice(0, 19).replace('T', ' ');
        document.getElementById("stop_value").value = datetime;
    }


</script>

我希望我已经充分描述了这个问题。如果缺少什么,请写信给我。请耐心等待,这是我的第一个问题。

【问题讨论】:

    标签: java spring jsp model-view-controller


    【解决方案1】:

    Bad 请求是由于这部分导致的绑定错误

    <form:hidden path="experiment" value="${experiment}"/>
    

    Spring MVC 使用 PropertyEditor 或 Converter 策略将对象类型(即 Experiment)转换为 String,以便在表单中使用该值。

    它还使用另一个转换器将表单上的字符串参数值转换为模型属性上的对象字段。您需要使用 Web 数据绑定器注册转换器。否则绑定到简单的属性,如实验 ID 并在控制器中查找对象

    1) 定义 ExperimentToStringConverter

       public class ExperimentToStringConverter implements  Converter<Experiment,String>{
    
          public String convert(Experiment experiment){
             return String.valueOf(experiment.getExperimentId());
          }
      }
    

    或者将 Experiment 中的 toString() 方法重写为

     public String toString(){
          return String.valueOf(experimentId);
     }
    

    这依赖于使用 toString() 方法的默认注册 ObjectToStringConverter

    2) 定义 StringToExperimentService

     public class StringToExperimentService implements Converter<String,Experiment>{
        public Experiment convert(String text){
           //lookup Experiment probably using  repository
        }
    }
    

    3) 向 Spring MVC 基础设施注册转换器

        @Configuration
        @EnableWebMvc
        public class ConsoleConfiguration extends WebMvcConfigurerAdapter{
           public void addFormatters(final FormatterRegistry registry) {
              super.addFormatters(registry);
              registry.addConverter(new ExperimentToStringConverter());
              registry.addConverter(new StringToExperimentConverter());
           }
        }
    

    如果您使用的是 xml 配置,您可以按如下方式注册您的转换器

    <mvc:annotation-driven conversion-service="conversionService"/>
    <bean id="conversionService"
          class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <list>
                <bean class="example.ExperimentToStringConverter"/>
                <bean class="example.StringToExperimentConverter"/>
            </list>
        </property>
    </bean>
    

    正如其他答案所指出的,您需要收集所有绑定和验证错误,以便您可以将它们报告给用户

    @RequestMapping(value = "/Testbereich/Versuch/saveTest", method = RequestMethod.POST)
    public ModelAndView saveTest(@ModelAttribute("test") Test test, BindingResult result) {
       if(result.hasErrors()){
          return new ModelAndView("TestView");
       }
       testservice.addTest(test);
       return new ModelAndView("redirect:/Uebersicht/Experiment");
     } 
    

    然后将 form:errors 添加到您的表单字段中

     <div class="col-8 offset-1">
        <form:input class="form-control" path="test_start" id="start_value" value="" disabled="true"></form:input>    
        <form:errors path="test_start"/>                          
    </div>
    

    【讨论】:

    • 感谢 ekem chitsiga 提供的有用答案。我认为这将是解决方案。我只有几个问题,必须点3)在spring servlet中实现吗?我用的是xml,有没有办法用xml写配置?
    • 我已更新答案以包含用于注册自定义转换器的 xml 配置
    • 不幸的是,它不能正常工作。我如何知道转换器是否正在使用?
    • 我不知道为什么,但是没有使用 ExperimentToStringConverter。然而,StringToExperimentConverter 已经存在。因此,此转换器中的字符串文本不包含实验 ID,而是包含作为字符串的对象(如“com.ibz.model.Experiment@7cab04ff”)。我该怎么做才能解决这个问题。
    【解决方案2】:

    要知道实际的字段错误问题试试这个

    @ModelAttribute

    之后添加BindingResult bindingResult
    @RequestMapping(value = "/Testbereich/Versuch/saveTest", method = RequestMethod.POST)
    public ModelAndView saveTest(@ModelAttribute("test") Test test, BindingResult bindingResult) {
    
    for( FieldError fieldError : bindingResult.getFieldErrors() )
        System.out.println(fieldError.getField() +" : "+fieldError.getDefaultMessage());
    
         testservice.addTest(test);
         return new ModelAndView("redirect:/Uebersicht/Experiment");
    }
    

    【讨论】:

      猜你喜欢
      • 2015-12-02
      • 1970-01-01
      • 2014-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-28
      • 2018-04-07
      • 1970-01-01
      相关资源
      最近更新 更多