【发布时间】:2022-02-03 16:52:16
【问题描述】:
我有一个 Question 列表,每个 Question 类型的对象与 Answer 类型的对象具有 1:n 关系(因此每个 Question 对象都有一个 Answer 对象列表)。我正在尝试使用 Angular 材料在浏览器上显示所有 Question 对象及其在单击事件后的答案,但是当我尝试这样做时,Question 对象在没有答案的情况下显示。经过一些研究,我发现即使Answer 和Question 对象正确“连接”并存储在数据库中,答案列表也未定义,如下面的控制台所示:
{id: 10, question: 'Question1', questionsForUser: Array(0), 答案: 未定义}
答案:homepage.component.ts:32
不明确的 homepage.component.ts:33
我该如何处理这个问题?
这里是Question和Answer的关系:
homepage.component 是发生以下点击事件的组件:
<div class="button">
<button mat-button (click)="getQuestions()" routerLink="questions/getAllQuestions" routerLinkActive="active">Show</button>
</div>
homepage.component.ts:
export class HomepageComponent implements OnInit {
longText = `...`;
public questions: Question[] = [];
constructor(private questionService: QuestionService, private shared: SharedService) { }
ngOnInit(): void {
this.shared.castQuestions.subscribe(questions=>this.questions=questions);
}
public getQuestions():void{
this.questionService.getQuestions().subscribe(
(response: Question[]) => {
this.questions =response;
this.shared.showQuestions(this.questions);
console.log(response);
for(let i=0; i<response.length; i++){
this.questions[i].answers=response[i].answers;
console.log(response[i]);
console.log("Answers:");
console.log(response[i].answers);
}
},
(error: HttpErrorResponse) => {
alert(error.message);
}
);
}
}
在点击事件之后,由于 Angular 路由,应该执行 tool.component 代码。
tool.component.html:
<table mat-table [dataSource]="questions" class="mat-elevation-z8">
<!-- Question Column -->
<ng-container matColumnDef="question">
<th mat-header-cell *matHeaderCellDef> Question </th>
<td mat-cell *matCellDef="let question"> {{question.question}} </td>
</ng-container>
<!-- Answers Column -->
<ng-container matColumnDef="answers">
<th mat-header-cell *matHeaderCellDef> Answers </th>
<td mat-cell *matCellDef="let question"> {{question.answers}} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
tool.component.ts:
export class ToolComponent implements OnInit {
public questions: Question[] = [];
displayedColumns = ['question', 'answers'];
constructor(private shared: SharedService) { }
ngOnInit(): void {
this.shared.castQuestions.subscribe(questions=>this.questions=questions);
}
}
shared.service.ts:
@Injectable({
providedIn: 'root'
})
export class SharedService {
private questions= new BehaviorSubject<Array<Question>>([]);
castQuestions = this.questions.asObservable();
showQuestions(data: Question[]){
this.questions.next(data);
}
}
console.log(响应):
question.service.ts:
@Injectable({
providedIn: 'root'
})
public getQuestions(): Observable<Question[]> {
return this.http.get<Question[]>('http://localhost:8080/questions/getAllQuestions');
}
}
我用来创建响应的返回/api:
问题实体:
@Getter
@Setter
@EqualsAndHashCode
@ToString
@Entity
@Table(name = "question", schema = "purchase")
public class Question {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private int id;
@Basic
@Column(name = "question", nullable = true, length = 1000)
private String question;
@OneToMany(mappedBy = "question", cascade = CascadeType.MERGE)
private List<QuestionForUser> questionsForUser;
@OneToMany(mappedBy = "question", cascade = CascadeType.MERGE)
@JsonIgnore
private List<Answer> answers;
}
回答实体:
@Getter
@Setter
@EqualsAndHashCode
@ToString
@Entity
@Table(name = "answer", schema = "purchase")
public class Answer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", nullable = false)
private int id;
@Basic
@Column(name = "answer", nullable = true, length = 1000)
private String answer;
@ManyToOne
@JoinColumn(name = "question")
private Question question;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
问题存储库:
@Repository
public interface QuestionRepository extends JpaRepository<Question, Integer> {
List<Question> findByQuestionContaining(String question);
boolean existsByQuestion(String question);
}
问题服务:
@Service
public class QuestionService {
@Autowired
private QuestionRepository questionRepository;
@Transactional(readOnly = true)
public List<Question> getAllQuestions(){
return questionRepository.findAll();
}
}
问题控制器:
@GetMapping("/getAllQuestions")
public List<Question> getAll(){
List<Question> ques = questionService.getAllQuestions();
for(Question q:ques){
System.out.println(q.getQuestion());
if(q.getAnswers()!=null){
System.out.println("The answers are: "+q.getAnswers().size());
}
}
return questionService.getAllQuestions();
}
按照建议,我尝试在QuestionController 中向getAll() 添加测试。为了让测试返回一个字符串,我暂时把getAll()的方法改成这样:
@GetMapping("/getAllQuestions")//funziona
public String getAll(){
List<Question> result = questionService.getAllQuestions();
String answer = result.get(0).getAnswers().get(0).getAnswer();
return answer;
}
然后,我编写了以下测试:
class QuestionControllerTest {
@Test
void getAll() {
QuestionController controller = new QuestionController(); //Arrange
String response = controller.getAll(); //Act
assertEquals("a1", response); //Assert
}
}
第一个问题的第一个答案应该是a1,但是当我在IntelliJ上执行测试时,结果如下:
java.lang.NullPointerException:无法调用 “com.ptoject.demo.services.QuestionService.getAllQuestions()”因为 “this.questionService”为空
在 com.ptoject.demo.controller.QuestionController.getAll(QuestionController.java:64) 在 com.ptoject.demo.controller.QuestionControllerTest.getAll(QuestionControllerTest.java:12) 在 java.base/java.util.ArrayList.forEach(ArrayList.java:1511)在 java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
【问题讨论】:
-
请在您的问题中添加此指令的控制台快照/捕获:console.log(response);
-
当然,我刚刚添加了快照。 @JuanVicenteBerzosaTejero
-
正如我所担心的那样,您会从您的背部/API 获得未定义的内容。您在 Angular 前端无能为力来解决它。您应该在“背面”方面遇到问题(除非您在“questionService”服务中遇到问题,在“getQuestions”方法中)。我建议您添加到您的质疑该方法“getQuestions() 的代码,以及用于创建“响应”对象的后台/API 的代码。
-
我将添加 questionService 服务和 back/API 的代码。谢谢@JuanVicenteBerzosaTejero
-
当然,问题似乎不在“getQuestions”方法中,而是在您的后端。 将您使用的语言的标签添加回您的原始问题。
标签: java spring typescript spring-boot angular-material