Spring Boot中如何通过实体属性校验实现条件删除?
问题与解决方案
问题描述
需要在执行deleteById()删除操作前,校验数据库中status列的值:仅当值为0或2时允许删除,值为1则禁止删除。业务逻辑放在Service层,但启动应用时出现依赖注入错误,提示找不到ReportRequest类型的Bean。
错误信息
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled. 2022-10-25 18:44:38.538 ERROR 2328 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPLICATION FAILED TO START *************************** Description: Parameter 0 of constructor in com.ssc.test.cb3.service.ReportRequestService required a bean of type 'com.ssc.test.cb3.model.ReportRequest' that could not be found. The injection point has the following annotations: - @org.springframework.beans.factory.annotation.Autowired(required=true) Action: Consider defining a bean of type 'com.ssc.test.cb3.model.ReportRequest' in your configuration. 2022-10-25 18:44:38.543 ERROR 2328 --- [ main] o.s.test.context.TestContextManager : Caught exception while allowing TestExecutionListener [org.springframework.test.context.web.ServletTestExecutionListener@7d446ed1] to prepare test instance [com.ssc.test.cb3.Cb3ApplicationTests@1f72fbd1] java.lang.IllegalStateException: Failed to load ApplicationContext Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.735 s <<< FAILURE! - in com.ssc.test.cb3.Cb3ApplicationTests contextLoads Time elapsed: 0.001 s <<< ERROR! java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reportRequestController': Unsatisfied dependency expressed through field 'reportRequestService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'reportRequestService' defined in file
错误末尾信息:
No qualifying bean of type 'com.ssc.test.cb3.model.ReportRequest' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
相关代码
模型类ReportRequest
package com.ssc.test.cb3.model; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; /** * Class that models the entity report request table of the database * @author ssc */ @Entity @Table(name = "report_request") @Data public class ReportRequest { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "seq_id") private int id; @Column(name = "request_date", insertable = false, nullable = true) private String requestDate; @Column(name = "request_userid") private int requestUserId; @Column(name = "request_email") private String requestEmail; @Column(name = "start_date") private String startDate; @Column(name = "end_date") private String endDate; @Column(name = "report_type") private int reportType; // 0 === cliente, 1 === proveedor @Column(name = "contact_id") private int contactId; @Column(name = "contact_id_customer") // Id from the client or provider chosen private int contactIdCustomer; @Column(name = "contact_id_provider") // Id from the provider or provider chosen private int contactIdProvider; private String rgids; private int status; // 0 === active, 1 === inactive @Column(name = "process_start") private String processStart; @Column(name = "process_finish") private String processFinish; @Column(name = "call_filter") // 0 === Answered calls, 1 === Not answered, 2 === both private int callQuery; @Column(name = "file_name") private String fileName; }
Repository类
package com.ssc.test.cb3.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.ssc.test.cb3.model.ReportRequest; /** * Class that extends to the repository for database management queries with * table report_request * * @author ssc */ @Repository public interface ReportRequestRepository extends JpaRepository<ReportRequest, Integer> { }
Service类(错误版本)
package com.ssc.test.cb3.service; import com.ssc.test.cb3.repository.ReportRequestRepository; import org.springframework.stereotype.Service; import com.ssc.test.cb3.model.ReportRequest; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; /** * Class to prepare the services to be dispatched upon request. * * @author ssc */ @Service @RequiredArgsConstructor @Slf4j public class ReportRequestService { @Autowired private ReportRequest reportRequest; private final ReportRequestRepository reportRequestRepository; /** * Function to delete a report from the database * * @param id from the report request objet to identify what is the specific * report */ // public void delete(int id) { // log.info("The report request {} was successfully deleted", id); // reportRequestRepository.deleteById(id); // } public void delete(int id) { if (reportRequest.getStatus() != 1) { log.info("The report request {} was successfully deleted", id); reportRequestRepository.deleteById(id); } else { log.error("It was not possible to delete the selected report as it hasn't been processed yet"); } } }
Controller类
package com.ssc.test.cb3.controller; import com.ssc.test.cb3.model.ReportRequest; import com.ssc.test.cb3.service.ReportRequestService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Class to handle REST services and APIs for the download Report's class * * @author ssc */ @RestController @RequestMapping("/v1/reportRequest") @CrossOrigin(origins = "http://localhost:3000") public class ReportRequestController { @Autowired private ReportRequestService reportRequestService; /** * Method to delete a report request by its id number, it will call the service method and passed the id captured * @param id */ @DeleteMapping("/delete/{id}") public void deleteReport(@PathVariable int id) { reportRequestService.delete(id); } }
解决方案
1. 修复依赖注入错误
错误根源是Service中尝试注入ReportRequest实体类,但ReportRequest是JPA实体,不是Spring管理的Bean(没有@Component等Spring注解),无法通过@Autowired注入。直接删除这行代码:
@Autowired private ReportRequest reportRequest;
2. 修正删除逻辑
要校验指定id的实体状态,需先通过Repository从数据库中查询该实体,再判断status值:
@Service @RequiredArgsConstructor @Slf4j public class ReportRequestService { private final ReportRequestRepository reportRequestRepository; public void delete(int id) { // 通过id查询实体,若不存在则抛出异常或处理 ReportRequest reportRequest = reportRequestRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("Report request with id " + id + " not found")); // 校验status:0或2允许删除,1禁止 if (reportRequest.getStatus() != 1) { reportRequestRepository.deleteById(id); log.info("The report request {} was successfully deleted", id); } else { log.error("Cannot delete report request {}: status is 1 (unprocessed)", id); // 可抛出自定义异常,让Controller返回对应HTTP状态码 throw new IllegalStateException("Cannot delete unprocessed report request"); } } }
3. 优化Controller返回结果
为了让前端感知删除结果,修改Controller方法返回ResponseEntity:
@DeleteMapping("/delete/{id}") public ResponseEntity<String> deleteReport(@PathVariable int id) { try { reportRequestService.delete(id); return ResponseEntity.ok("Report request deleted successfully"); } catch (IllegalArgumentException e) { return ResponseEntity.status(HttpStatus.NOT_FOUND).body(e.getMessage()); } catch (IllegalStateException e) { return ResponseEntity.status(HttpStatus.FORBIDDEN).body(e.getMessage()); } }
这样既解决了依赖注入错误,又实现了删除前的状态校验逻辑,同时给前端返回明确的响应结果。
内容的提问来源于stack exchange,提问作者Rosh343
相关产品推荐
相关产品推荐

