【问题标题】:JPA, Spring web - how to "find" non-existent record in databaseJPA,Spring web - 如何在数据库中“查找”不存在的记录
【发布时间】:2014-04-14 22:44:55
【问题描述】:

我在 Spring 中编写了 web。我将 Hibernate 用于 JPA。我需要在数据库中查找实体,我从用户那里获取 ID。

问题是如果 ID 不在数据库中 - 我得到 NullPointerException。

现在我有:

People p;
try {
  p = peopleManager.findById(id);
  if (p != null) {
    model.addAttribute("message", "user exist, do any action");
  } else {
    model.addAttribute("message", "user NOT exist");
  }
} catch (NullPointerException e) {
  model.addAttribute("message", "user NOT exist");
}

但它看起来很糟糕。我怎样才能做到正确?

有完整的示例代码:

package com.example.test.entity;

import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

public class People {  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id")
  private int id;

  @Column(name="name")
  private String name;

  @Column(name="age")
  private int age;
}
/* ---------------------------------------------------- */
package com.example.test.dao;

import java.util.List;
import com.example.test.entity.People;

public interface PeopleDao {  
    public void save(People people);  
    public void delete(People people);    
    public void update(People people); 
    public List<People> findAll();    
    public People findById(int id);
}
/* ---------------------------------------------------- */
package com.example.test.dao;

import java.util.List;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.test.entity.People;

@Repository
public class PeopleDaoImpl implements PeopleDao {

  @Autowired
  private SessionFactory sessionFactory;

  @Override
  public void save(People people) {
    this.sessionFactory.getCurrentSession().save(people);    
  }
  @Override
  public void delete(People people) {
    this.sessionFactory.getCurrentSession().delete(people);    
  }
  @Override
  public void update(People people) {
    this.sessionFactory.getCurrentSession().update(people);    
  }
  @Override
  public List<People> findAll() {
    return this.sessionFactory.getCurrentSession().createQuery("from People ORDER BY age").list();
  }
  @Override
  public People findById(int id) {
    return (People) this.sessionFactory.getCurrentSession().get(People.class, id);
  }
}
/* ---------------------------------------------------- */
package com.example.test.service;

import java.util.List;
import com.example.test.entity.People;

public interface PeopleManager {  
  public void save(People people);  
    public void delete(People people);    
    public void update(People people); 
    public List<People> findAll();    
    public People findById(int id);
}
/* ---------------------------------------------------- */
package com.example.test.service;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.test.dao.PeopleDao;
import com.example.test.entity.People;

@Service
@Transactional
public class PeopleManagerImpl implements PeopleManager {

  @Autowired
  private PeopleDao peopleDao;

  @Override
  public void save(People people) {
    peopleDao.save(people);  
  }
  @Override
  public void delete(People people) {
    peopleDao.delete(people);    
  }
  @Override
  public void update(People people) {
    peopleDao.update(people);
  }
  @Override
  public List<People> findAll() {
    return peopleDao.findAll();
  }
  @Override
  public People findById(int id) {
    return peopleDao.findById(id);
}
/* ---------------------------------------------------- */
package com.example.test.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.example.test.entity.People;
import com.example.test.service.PeopleManager;

@Controller
public class PeopleController {  
  @Autowired
  private PeopleManager peopleManager;

  @RequestMapping(value = "/people/{id}", method = RequestMethod.GET)
  public String home(Model model, @PathVariable("id") String id) {    
    People p;
    try {
      p = peopleManager.findById(Integer.parseInt(id));
      if (p != null) {
        model.addAttribute("message", "user exist, do any action");
      } else {
        model.addAttribute("message", "user NOT exist");
      }
    } catch (NullPointerException e) {
      model.addAttribute("message", "user NOT exist");
    }
    return "people";
  }  
}
/* ---------------------------------------------------- */

【问题讨论】:

  • NPE 从何而来? Hibernate javadoc 说get() 方法如果找不到则返回 null,而不是抛出 NPE
  • 我使用 getEntityManager().find(clazz, id),从来没有得到 NullPointerException

标签: java spring hibernate jpa model-view-controller


【解决方案1】:

重构控制器的空检查。控制器中不应包含任何业务逻辑。正确的位置是在您的服务类中。

@Override
@Transactional
public People findById(int id) throws ObjectNotFoundException{
    People people = null;        
    people  = peopleDao.findById(id);
    if(people == null){
        throw new ObjectNotFoundException("Couldn't find a People object with id " + id);
    }
    return people;
}

如果您的 People 对象为空,我会编写一个扩展 RuntimeException 的自定义异常。

这是最佳实践,因为您可以在所有服务层中重用 ObjectNotFoundException。然后让你的所有控制器方法抛出Exception 并调查控制器的全局错误处理。

此外,最好不要将整个服务类注释为@Transactional,标记各个方法。这样,如果您需要向服务添加其他方法,您可以选择是否希望它们在事务上下文中运行。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-01
    • 2022-01-13
    • 1970-01-01
    • 1970-01-01
    • 2021-07-31
    • 1970-01-01
    • 2020-01-21
    • 1970-01-01
    相关资源
    最近更新 更多