非空属性引用空值或瞬态值-Spring Boot-Thymeleaf

如何解决非空属性引用空值或瞬态值-Spring Boot-Thymeleaf

我的网络应用程序更新存在问题。

每次我尝试更新一个元素时,我都会收到此错误: not-null属性引用的是null或瞬态值:me.lucacirfeta.model.Element.user

要解决此问题,我需要在表单内部添加一个隐藏有User模型的所有变量的输入,例如:

<input th:field="${element.user.id}" class="form-control" type="text" readonly />
<input th:field="${element.user.username}" class="form-control" type="text" readonly />
<input th:field="${element.user.firstName}" class="form-control" type="text" readonly />
<input th:field="${element.user.lastName}" class="form-control" type="text" readonly />
<input th:field="${element.user.password}" class="form-control" type="text" readonly />

但是我不想在表单上添加此隐藏数据。 我还尝试在JoinColumn批注中删除Element模型中的“ nullable = false”,但是当我尝试更新时,Hibernate丢失了用户将其设置为“ null”的引用。

我该如何解决?

这是我的代码:

型号

package me.lucacirfeta.model;
// default package

// Generated 29-lug-2020 10.31.08 by Hibernate Tools 4.3.5.Final

import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * Element generated by hbm2java
 */
@Entity
@Table(name = "ELEMENT",schema = "TEST")
public class Element implements java.io.Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 7331854204646419731L;
    
    private long id;
    private ElDate elDate;
    private Period period;
    private User user;
    private PlaceOfDiscovery placeOfDiscovery;
    private ElType elType;
    private ElDimension elDimension;
    private String description;
    private String otherDetails;
    private Date created;
    private boolean validation;
    private Date discoveryDate;
    
    private Set<ElementImage> elementImages = new HashSet<ElementImage>(0);

    public Element() {
    }

    @Id
    @Column(name = "ID",unique = true,nullable = false,precision = 22,scale = 0)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public long getId() {
        return this.id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_DATE",nullable=false,insertable=false)
    public ElDate getElDate() {
        return this.elDate;
    }

    public void setElDate(ElDate elDate) {
        this.elDate = elDate;
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_PERIOD",insertable=false)
    public Period getPeriod() {
        return this.period;
    }

    public void setPeriod(Period period) {
        this.period = period;
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_USER",insertable=false)
    public User getUser() {
        return this.user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_PLACE_OF_DISCOVERY")
    public PlaceOfDiscovery getPlaceOfDiscovery() {
        return this.placeOfDiscovery;
    }

    public void setPlaceOfDiscovery(PlaceOfDiscovery placeOfDiscovery) {
        this.placeOfDiscovery = placeOfDiscovery;
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_EL_TYPE",insertable=false)
    public ElType getElType() {
        return this.elType;
    }

    public void setElType(ElType elType) {
        this.elType = elType;
    }

    @ManyToOne(fetch = FetchType.LAZY,cascade = {CascadeType.ALL})
    @JoinColumn(name = "ID_EL_DIMENSION",insertable=false)
    public ElDimension getElDimension() {
        return this.elDimension;
    }

    public void setElDimension(ElDimension elDimension) {
        this.elDimension = elDimension;
    }

    @Column(name = "DESCRIPTION")
    public String getDescription() {
        return this.description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    @Column(name = "OTHER_DETAILS")
    public String getOtherDetails() {
        return this.otherDetails;
    }

    public void setOtherDetails(String otherDetails) {
        this.otherDetails = otherDetails;
    }

    @Column(name = "CREATED")
    @Temporal(TemporalType.TIMESTAMP)
    public Date getCreated() {
        return this.created;
    }

    public void setCreated(Date created) {
        this.created = created;
    }

    @Column(name = "VALIDATION",precision = 1,scale = 0)
    public boolean isValidation() {
        return this.validation;
    }

    public void setValidation(boolean validation) {
        this.validation = validation;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "DISCOVERY_DATE",length = 7)
    public Date getDiscoveryDate() {
        return this.discoveryDate;
    }

    public void setDiscoveryDate(Date discoveryDate) {
        this.discoveryDate = discoveryDate;
    }

    @OneToMany(fetch = FetchType.LAZY,mappedBy = "element",cascade = {CascadeType.ALL})
    public Set<ElementImage> getElementImages() {
        return this.elementImages;
    }

    public void setElementImages(Set<ElementImage> elementImages) {
        this.elementImages = elementImages;
    }
    
}

控制器

package me.lucacirfeta.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import me.lucacirfeta.model.Element;
import me.lucacirfeta.service.ElementService;
import me.lucacirfeta.service.ServiceException;

@Controller
@RequestMapping(value = "/admin/update/{id}")
public class AdminUpdateElementController {

    @Autowired
    private ElementService elementService;

    @GetMapping
    public ModelAndView updateElement(@PathVariable(name = "id") Long id) {
        Element element = null;

        try {
            element = elementService.findById(id);

        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }
        ModelAndView mv = new ModelAndView("updateElement");
        mv.addObject("element",element);
        
        return mv;
    }

    @PostMapping
    @RequestMapping(value = "/formUpdate")
    public String formUpdateElement(@ModelAttribute Element element) {

        try {
            this.elementService.update(element);
        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }

        return "redirect:/admin/elements";
    }

}

application.properties

# ===============================
# = DATA SOURCE
# ===============================

# Set here configurations for the database connection

# Connection url for the database "netgloo_blog"
spring.datasource.url= jdbc:****

# Username and password
spring.datasource.username= ****
spring.datasource.password= ****

spring.datasource.driver-class-name= com.mysql.cj.jdbc.Driver

# Keep the connection alive if idle for a long time (needed in production)
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1

# ===============================
# = JPA / HIBERNATE
# ===============================

# Show or not log for each sql query
spring.jpa.show-sql = false
spring.jpa.hibernate.format_sql= true

# Hibernate ddl auto (create,create-drop,update): with "update" the database
# schema will be automatically updated accordingly to java entities found in
# the project
spring.jpa.hibernate.ddl-auto = update

# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy

# Allows Hibernate to generate SQL optimized for a particular DBMS
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5InnoDBDialect

# ===============================
# = OTHERS
# ===============================

entitymanager.packagesToScan= me.lucacirfeta

server.port=8081

server.session.timeout=15

spring.mvc.hiddenmethod.filter.enabled=true

logging.level.org.springframework.web=DEBUG

html页面

<!DOCTYPE html>
<html lang="it" xmlns:th="http://www.thymeleaf.org">

<head>
    <div th:replace="header :: header"></div>
    <link th:href="@{/css/style.css}" rel="stylesheet" type="text/css" />
    <title th:text="Aggiorna + ' ' + Elemento + ' ' + ID + ' ' + ${element.id}"></title>
</head>

<body>

    <div th:insert="navbar :: navbar"></div>
    <h2 style="text-align: center;">Aggiorna Elemento</h2>
    <!--  Start of main body of record -->
    <div class="container-fluid" style="width: 60%;">
        <!--  Start of descriptive data -->
        <div class="row-fluid">
            <div>

                <form th:action="@{'/admin/update/' + ${element.id} + '/formUpdate'}" th:object="${element}"
                    th:method="post">

                    <!-- Header of section -->
                    <hr>
                    <p><strong>ID Univoco:</strong> <span th:text="${id}"></span></p>
                    <div class="form-group">
                        <h1 class="lead">Tipo</h1>
                        <input th:field="*{elType.elementType}" type="text" class="form-control" />
                    </div>
                    <!-- The description of the object -->
                    <div>
                        <div class="form-group">
                            <h4 class="lead">Descrizione</h4>
                            <textarea rows="5" th:field="*{description}" class="form-control"></textarea>
                        </div>
                    </div>
                    <p>
                    </p>
                    <!-- Others details -->
                    <div class="form-group">
                        <h4 class="lead">Altri dettagli</h4>
                        <textarea th:field="*{otherDetails}" class="form-control"></textarea>
                    </div>

                    <div class="container" style="display: flex; justify-content: space-between;">
                        <div class="row">
                            <div class="col">

                                <h4 class="lead">Cronologia</h4>
                                <p>
                                    Periodo dal: <input th:field="${element.Period.periodFrom}" class="form-control"
                                        type="text" />
                                    Periodo al: <input th:field="${element.Period.periodTo}" class="form-control"
                                        type="text" />
                                    Data dal: Circa AD <input th:field="${element.elDate.dateFrom}" class="form-control"
                                        type="text" />
                                    Data al: Circa AD <input th:field="${element.elDate.dateTo}" class="form-control"
                                        type="text" />

                                </p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col">

                                <h4 class="lead">Dimensioni e Peso</h4>
                                <p>
                                    Lunghezza: mm <input th:field="${element.elDimension.elLength}" class="form-control"
                                        type="text" />
                                    Peso: g. <input th:field="${element.elDimension.elWeight}" class="form-control"
                                        type="text" />
                                    Spessore: g. <input th:field="${element.elDimension.elThickness}"
                                        class="form-control" type="text" />
                                    Diametro: mm <input th:field="${element.elDimension.elDiameter}"
                                        class="form-control" type="text" />

                                </p>
                            </div>
                        </div>

                        <div class="row">
                            <div class="col">
                                <h4 class="lead">Materiale</h4>
                                <p>
                                    Materiale: <input th:field="${element.elType.material}" class="form-control"
                                        type="text" />
                                </p>
                            </div>
                        </div>
                    </div>

                    <div class="container" style="display: flex; justify-content: space-between;">
                        <div class="row">
                            <div class="col">
                                <h4 class="lead">Validazione</h4>
                                <p>
                                    <input th:field="${element.validation}" class="form-control" type="text" />
                                </p>
                            </div>
                        </div>
                        <div class="row">
                            <div class="col">
                                <h4 class="lead">User</h4>
                                <p>
                                    <input th:field="${element.user.id}" class="form-control" type="text" readonly />
                                    <input th:field="${element.user.username}" class="form-control" type="text"
                                        readonly />
                                    <input th:field="${element.user.firstName}" class="form-control" type="text"
                                        readonly />
                                    <input th:field="${element.user.lastName}" class="form-control" type="text"
                                        readonly />
                                    <input th:field="${element.user.password}" class="form-control" type="text"
                                        readonly />
                                </p>
                            </div>
                        </div>
                    </div>

                    <div class="form-group">
                        <button class="btn btn-primary" type="submit">Aggiorna</button>
                    </div>
                </form>
                <!-- End of descriptive data -->
            </div>
        </div>
    </div>
    <div th:insert="scripts :: scripts"></div>
</body>

</html>

解决方法

在这种情况下,最好创建一个简单的DTO类,例如ElementDTO

public class ElementDTO {
    //all the fields that you need,getters,setters and default constructor
}

然后通过在控制器中添加以下方法将其传递给更新表单

@ModelAttribute("element")
public ElementDTO elementDTO(){
    return new ElementDTO();
}

这种方法更好的原因有几个:

  1. 您不需要在每次加载表单时都预先从数据库中加载对象
  2. 您只需定义要更新的字段,而不必担心非空字段上的休眠规则。

然后在controlle方法中期望对象只是将参数更改为(ElementDTO elementDTO)并将所有更新的字段复制到actial Element对象,然后将其保存在数据库中

,

我找到了解决方法。

我在添加有@SessionAttributes的会话中使用一个元素,并且没有丢失与User的引用。

这是已编辑的控制器:

package me.lucacirfeta.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;

import me.lucacirfeta.model.Element;
import me.lucacirfeta.service.ElementService;
import me.lucacirfeta.service.ServiceException;

@Controller
@RequestMapping(value = "/admin/update/{id}")
@SessionAttributes(value = "element")
public class AdminUpdateElementController {

    @Autowired
    private ElementService elementService;

    @ModelAttribute("element")
    public Element updateElement(@PathVariable(name = "id") Long id) {

        Element element = null;

        try {
            element = elementService.findById(id);

        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }

        return element;
    }

    @GetMapping
    public String updateElement() {
        return "updateElement";
    }

    @PostMapping
    @RequestMapping(value = "/formUpdate")
    public String formUpdateElement(Element element) {

        try {
            this.elementService.update(element);
        } catch (ServiceException e) {
            System.out.println(e.getMessage());
        }

        return "redirect:/admin/elements";
    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-