全栈前端出现奇怪错误 Spring Boot academic project
Strange error in front-end of full-stack Spring Boot academic project
我们被要求为一个学术项目开发一个使用 Java、Maven 和 Spring-Boot 的全栈网络系统,试图遵循 CLEAN 架构和 SOLID原则。老师告诉我,最重要的目标是让后端和前端沟通。我开发的系统很瘦,由几个后端 Java 类 和 MySQL db 和一个简化的前端组成,有 2 HTML 个文件和简洁的 CSS和Java脚本代码。
前端页面包含两个JS异步函数;第一个通过其 id 属性检索食谱名称,另一个尝试检索存储在其各自 MySQL db table 中的完整食谱列表,通过以下 JPA @Query 注释:
@Query (value = "SELECT matricula, registro, nome FROM RECEITA", nativeQuery = true)
预期返回值为:
但实际显示的结果是:
我会认为我在编程方面的专业水平是初学者;不知道哪里错了,涉及的方法和文件太多了。我会粘贴代码,这样也许有人会指出可能的错误。
项目文件夹结构:
App.java:
package com.pucrs.grupo2.Recipes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@ComponentScan(basePackages = "com.pucrs.grupo2")
@EnableJpaRepositories(basePackages = {"com.pucrs.grupo2"}) // onde procurar as interfaces dos repositórios do JPA
@EntityScan(basePackages = {"com.pucrs.grupo2"}) // onde procurar as entidades
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
ClienteFachadaRemota.java:
package com.pucrs.grupo2.Recipes.interfaces;
import java.util.List;
import com.pucrs.grupo2.Recipes.services.ServicoReceitas;
import com.pucrs.grupo2.Recipes.models.Receita;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/consulta_receita")
public class ClienteFachadaRemota {
private ServicoReceitas sConsultaRec;
@Autowired
public ClienteFachadaRemota (ServicoReceitas sConsultaRec) {
this.sConsultaRec = sConsultaRec;
}
@CrossOrigin(origins = "*")
@GetMapping("/dadosreceita")
public Receita getDadosReceita(@RequestParam Long matricula) {
Receita receita = sConsultaRec.getNomeReceita(matricula);
return receita;
}
@CrossOrigin(origins = "*")
@GetMapping("/listareceitas")
public List<Receita> getTabelaReceitas() {
List<Receita> receitas = sConsultaRec.findTables();
return receitas;
}
}
Receita.java:
package com.pucrs.grupo2.Recipes.models;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "receita")
public class Receita {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long matricula;
private int registro;
private String nome;
public Receita() {
}
public Receita(int registro, String nome) {
this.registro = registro;
this.nome = nome;
}
public Long getMatricula() {
return matricula;
}
public int getRegistro() {
return registro;
}
public void setRegistro(int registro) {
this.registro = registro;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Override
public String toString() {
return "Receita [matricula=" + getMatricula() + ", registro=" + getRegistro() + ", nome=" + getNome() + "]";
}
}
RepositorioReceitas.java:
package com.pucrs.grupo2.Recipes.repositories;
import java.util.List;
import com.pucrs.grupo2.Recipes.models.Receita;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.jpa.repository.Query;
public interface RepositorioReceitas extends CrudRepository<Receita, Long> {
List<Receita> findByMatricula(long matricula);
List<Receita> findAll();
@Query (value = "SELECT matricula, registro, nome FROM RECEITA", nativeQuery = true)
List<Receita> findTables();
}
ServicoReceitas.java:
package com.pucrs.grupo2.Recipes.services;
import com.pucrs.grupo2.Recipes.models.Receita;
import com.pucrs.grupo2.Recipes.repositories.RepositorioReceitas;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ServicoReceitas {
private RepositorioReceitas repReceitas;
private Receita cacheReceita;
@Autowired
public ServicoReceitas(RepositorioReceitas repReceitas) {
this.repReceitas = repReceitas;
cacheReceita = null;
}
public Receita getNomeReceita(long matricula) {
List<Receita> receitas = repReceitas.findByMatricula(matricula);
if (receitas.size() == 0){
throw new IllegalArgumentException("Receita nao encontrada");
} else {
cacheReceita = receitas.get(0) ;
return cacheReceita;
}
}
public List<Receita> listaDeReceitas() {
List<Receita> receitas = repReceitas.findAll();
return receitas;
}
public List<Receita> findTables() {
List<Receita> receitas = repReceitas.findTables();
return receitas;
}
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Retrieval by id, List Retrieval Recipes System </title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Retrieval by id, Recipe List Retrieval System</h1>
<ul>
<li>
<label for="matricula">id:</label>
<input type="text" id="matricula" name="matricula">
</li>
<li>
<label id="nome">Nome:</label>
<span id="nomeReceita"> - </span>
</li>
<li>
<button id="btDados">Consultar Nome</button>
<span id="erro"></span>
<br>
<button id="btLista">Mostrar Lista</button>
<span id="listareceitas"> - </span>
</li>
</ul>
<script type="text/javascript" src="./script.js"></script>
</body>
</html>
style.css:
.recipes-icon {
content:url(file:///D:/Documentos/Docs/PUCRS/FdDdSW/TF/TF-FDS/Recipes/src/main/resources/static/r_spatula.jpg);
width: 800px;
height: 600px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
div {
position: fixed;
color: brown;
font-family: sans-serif;
font-size: 300%;
left: 50%;
bottom: 100px;
transform:translate(-50%, -50%);
margin: 0 auto;
cursor: pointer;
}
h1 {
color: brown;
width: 100%;
text-align: center;
}
.ul {
list-style: none;
padding: 0;
margin: 0;
}
.label {
display: inline-block;
width: 90px;
text-align: right;
}
.input {
font: 1em sans-serif;
width: 300px;
box-sizing: border-box;
border: 1px solid #999;
}
.input:focus {
border-color: #000;
}
.button {
margin:auto;
text-align: center;
}
#erro {
color:red;
}
script.js:
//Consulta nome da receita pelo id
async function consultaNomeReceita(matricula) {
//console.log(matricula);
let url = "http://localhost:8080/consulta_receita/dadosreceita";
url = url + "?matricula="+matricula;
try {
let resposta = await fetch(url);
//console.log(resposta);
if (resposta.ok){
let dados = await resposta.json();
//console.log(dados);
return dados;
}else{
//console.log(resposta.status+", text="+resposta.statusText);
return null;
}
}catch(erro){
console.log(erro);
}
}
//Mostra Lista Receitas
async function listaReceitas() {
//console.log(matricula);
let url = "http://localhost:8080/consulta_receita/listareceitas";
//url = url + "?matricula="+matricula;
try {
let resposta = await fetch(url);
//console.log(resposta);
if (resposta.ok) {
let dados = await resposta.json();
//console.log(dados);
return dados;
} else {
//console.log(resposta.status+", text="+resposta.statusText);
return null;
}
} catch(erro) {
console.log(erro);
}
}
// --- início do programa
document.getElementById("btDados").onclick = async function () {
let matricula = document.getElementById("matricula").value;
let resposta = await consultaNomeReceita(matricula);
if (resposta != null){
let nome = document.getElementById("nomeReceita");
nome.innerHTML = resposta.nome;
erro = document.getElementById("erro");
erro.innerHTML = "";
//let json = document.getElementById("jsonValor");
//json.innerHTML = JSON.stringify(resposta);
} else {
let nome = document.getElementById("nomeReceita");
nome.innerHTML = " - ";
erro = document.getElementById("erro");
erro.innerHTML = "Erro na consulta dos dados";
}
}
document.getElementById("btLista").onclick = async function () {
let resposta = await listaReceitas();
if (resposta != null){
let tables = document.getElementById("listareceitas");
tables.innerHTML = resposta;
erro = document.getElementById("erro");
erro.innerHTML = "";
//let json = document.getElementById("jsonValor");
//json.innerHTML = JSON.stringify(resposta);
} else {
let tables = document.getElementById("listareceitas");
tables.innerHTML = " - ";
erro = document.getElementById("erro");
erro.innerHTML = "Erro na consulta dos dados";
}
}
有什么想法吗?
项目的 GitHub 回购 URL:Recipes system
在您的 script.js 文件的最后一段代码中,您试图显示整个 JSON 检索到的对象,您应该遍历整个结果 respota 并将其显示到前端: 应该是这样的:
const response = await fetch('http://localhost:3000/users/');
const data = await response.json();
data.forEach(obj => {
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`);
});
console.log('-------------------');
});
您可能会发现此 url 也很有用:http://zetcode.com/javascript/jsonforeach/
如@Bleard Rexhaj 所述,您的数据包含一个数组,您可以将代码更改为以下内容。此外,我会考虑为 UI 使用 Javascript 框架,它将大大提高代码的质量。我会考虑的一些流行的是 React.js 或 Vue.js.
document.getElementById("btLista").onclick = async function () {
let resposta = await listaReceitas();
if (resposta != null){
let tables = document.getElementById("listareceitas");
let innerHTML = '';
resposta.forEach(obj => {
innerHTML += ' - ' + obj.nome;
});
tables.innerHTML = innerHTML;
erro = document.getElementById("erro");
erro.innerHTML = "";
} else {
let tables = document.getElementById("listareceitas");
tables.innerHTML = " - ";
erro = document.getElementById("erro");
erro.innerHTML = "Erro na consulta dos dados";
}
}
我们被要求为一个学术项目开发一个使用 Java、Maven 和 Spring-Boot 的全栈网络系统,试图遵循 CLEAN 架构和 SOLID原则。老师告诉我,最重要的目标是让后端和前端沟通。我开发的系统很瘦,由几个后端 Java 类 和 MySQL db 和一个简化的前端组成,有 2 HTML 个文件和简洁的 CSS和Java脚本代码。
前端页面包含两个JS异步函数;第一个通过其 id 属性检索食谱名称,另一个尝试检索存储在其各自 MySQL db table 中的完整食谱列表,通过以下 JPA @Query 注释:
@Query (value = "SELECT matricula, registro, nome FROM RECEITA", nativeQuery = true)
预期返回值为:
但实际显示的结果是:
我会认为我在编程方面的专业水平是初学者;不知道哪里错了,涉及的方法和文件太多了。我会粘贴代码,这样也许有人会指出可能的错误。
项目文件夹结构:
App.java:
package com.pucrs.grupo2.Recipes;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
@SpringBootApplication
@ComponentScan(basePackages = "com.pucrs.grupo2")
@EnableJpaRepositories(basePackages = {"com.pucrs.grupo2"}) // onde procurar as interfaces dos repositórios do JPA
@EntityScan(basePackages = {"com.pucrs.grupo2"}) // onde procurar as entidades
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
ClienteFachadaRemota.java:
package com.pucrs.grupo2.Recipes.interfaces;
import java.util.List;
import com.pucrs.grupo2.Recipes.services.ServicoReceitas;
import com.pucrs.grupo2.Recipes.models.Receita;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/consulta_receita")
public class ClienteFachadaRemota {
private ServicoReceitas sConsultaRec;
@Autowired
public ClienteFachadaRemota (ServicoReceitas sConsultaRec) {
this.sConsultaRec = sConsultaRec;
}
@CrossOrigin(origins = "*")
@GetMapping("/dadosreceita")
public Receita getDadosReceita(@RequestParam Long matricula) {
Receita receita = sConsultaRec.getNomeReceita(matricula);
return receita;
}
@CrossOrigin(origins = "*")
@GetMapping("/listareceitas")
public List<Receita> getTabelaReceitas() {
List<Receita> receitas = sConsultaRec.findTables();
return receitas;
}
}
Receita.java:
package com.pucrs.grupo2.Recipes.models;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "receita")
public class Receita {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long matricula;
private int registro;
private String nome;
public Receita() {
}
public Receita(int registro, String nome) {
this.registro = registro;
this.nome = nome;
}
public Long getMatricula() {
return matricula;
}
public int getRegistro() {
return registro;
}
public void setRegistro(int registro) {
this.registro = registro;
}
public String getNome() {
return nome;
}
public void setNome(String nome) {
this.nome = nome;
}
@Override
public String toString() {
return "Receita [matricula=" + getMatricula() + ", registro=" + getRegistro() + ", nome=" + getNome() + "]";
}
}
RepositorioReceitas.java:
package com.pucrs.grupo2.Recipes.repositories;
import java.util.List;
import com.pucrs.grupo2.Recipes.models.Receita;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.jpa.repository.Query;
public interface RepositorioReceitas extends CrudRepository<Receita, Long> {
List<Receita> findByMatricula(long matricula);
List<Receita> findAll();
@Query (value = "SELECT matricula, registro, nome FROM RECEITA", nativeQuery = true)
List<Receita> findTables();
}
ServicoReceitas.java:
package com.pucrs.grupo2.Recipes.services;
import com.pucrs.grupo2.Recipes.models.Receita;
import com.pucrs.grupo2.Recipes.repositories.RepositorioReceitas;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class ServicoReceitas {
private RepositorioReceitas repReceitas;
private Receita cacheReceita;
@Autowired
public ServicoReceitas(RepositorioReceitas repReceitas) {
this.repReceitas = repReceitas;
cacheReceita = null;
}
public Receita getNomeReceita(long matricula) {
List<Receita> receitas = repReceitas.findByMatricula(matricula);
if (receitas.size() == 0){
throw new IllegalArgumentException("Receita nao encontrada");
} else {
cacheReceita = receitas.get(0) ;
return cacheReceita;
}
}
public List<Receita> listaDeReceitas() {
List<Receita> receitas = repReceitas.findAll();
return receitas;
}
public List<Receita> findTables() {
List<Receita> receitas = repReceitas.findTables();
return receitas;
}
}
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> Retrieval by id, List Retrieval Recipes System </title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Retrieval by id, Recipe List Retrieval System</h1>
<ul>
<li>
<label for="matricula">id:</label>
<input type="text" id="matricula" name="matricula">
</li>
<li>
<label id="nome">Nome:</label>
<span id="nomeReceita"> - </span>
</li>
<li>
<button id="btDados">Consultar Nome</button>
<span id="erro"></span>
<br>
<button id="btLista">Mostrar Lista</button>
<span id="listareceitas"> - </span>
</li>
</ul>
<script type="text/javascript" src="./script.js"></script>
</body>
</html>
style.css:
.recipes-icon {
content:url(file:///D:/Documentos/Docs/PUCRS/FdDdSW/TF/TF-FDS/Recipes/src/main/resources/static/r_spatula.jpg);
width: 800px;
height: 600px;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
div {
position: fixed;
color: brown;
font-family: sans-serif;
font-size: 300%;
left: 50%;
bottom: 100px;
transform:translate(-50%, -50%);
margin: 0 auto;
cursor: pointer;
}
h1 {
color: brown;
width: 100%;
text-align: center;
}
.ul {
list-style: none;
padding: 0;
margin: 0;
}
.label {
display: inline-block;
width: 90px;
text-align: right;
}
.input {
font: 1em sans-serif;
width: 300px;
box-sizing: border-box;
border: 1px solid #999;
}
.input:focus {
border-color: #000;
}
.button {
margin:auto;
text-align: center;
}
#erro {
color:red;
}
script.js:
//Consulta nome da receita pelo id
async function consultaNomeReceita(matricula) {
//console.log(matricula);
let url = "http://localhost:8080/consulta_receita/dadosreceita";
url = url + "?matricula="+matricula;
try {
let resposta = await fetch(url);
//console.log(resposta);
if (resposta.ok){
let dados = await resposta.json();
//console.log(dados);
return dados;
}else{
//console.log(resposta.status+", text="+resposta.statusText);
return null;
}
}catch(erro){
console.log(erro);
}
}
//Mostra Lista Receitas
async function listaReceitas() {
//console.log(matricula);
let url = "http://localhost:8080/consulta_receita/listareceitas";
//url = url + "?matricula="+matricula;
try {
let resposta = await fetch(url);
//console.log(resposta);
if (resposta.ok) {
let dados = await resposta.json();
//console.log(dados);
return dados;
} else {
//console.log(resposta.status+", text="+resposta.statusText);
return null;
}
} catch(erro) {
console.log(erro);
}
}
// --- início do programa
document.getElementById("btDados").onclick = async function () {
let matricula = document.getElementById("matricula").value;
let resposta = await consultaNomeReceita(matricula);
if (resposta != null){
let nome = document.getElementById("nomeReceita");
nome.innerHTML = resposta.nome;
erro = document.getElementById("erro");
erro.innerHTML = "";
//let json = document.getElementById("jsonValor");
//json.innerHTML = JSON.stringify(resposta);
} else {
let nome = document.getElementById("nomeReceita");
nome.innerHTML = " - ";
erro = document.getElementById("erro");
erro.innerHTML = "Erro na consulta dos dados";
}
}
document.getElementById("btLista").onclick = async function () {
let resposta = await listaReceitas();
if (resposta != null){
let tables = document.getElementById("listareceitas");
tables.innerHTML = resposta;
erro = document.getElementById("erro");
erro.innerHTML = "";
//let json = document.getElementById("jsonValor");
//json.innerHTML = JSON.stringify(resposta);
} else {
let tables = document.getElementById("listareceitas");
tables.innerHTML = " - ";
erro = document.getElementById("erro");
erro.innerHTML = "Erro na consulta dos dados";
}
}
有什么想法吗?
项目的 GitHub 回购 URL:Recipes system
在您的 script.js 文件的最后一段代码中,您试图显示整个 JSON 检索到的对象,您应该遍历整个结果 respota 并将其显示到前端: 应该是这样的:
const response = await fetch('http://localhost:3000/users/'); const data = await response.json();
data.forEach(obj => {
Object.entries(obj).forEach(([key, value]) => {
console.log(`${key} ${value}`);
});
console.log('-------------------');
});
您可能会发现此 url 也很有用:http://zetcode.com/javascript/jsonforeach/
如@Bleard Rexhaj 所述,您的数据包含一个数组,您可以将代码更改为以下内容。此外,我会考虑为 UI 使用 Javascript 框架,它将大大提高代码的质量。我会考虑的一些流行的是 React.js 或 Vue.js.
document.getElementById("btLista").onclick = async function () {
let resposta = await listaReceitas();
if (resposta != null){
let tables = document.getElementById("listareceitas");
let innerHTML = '';
resposta.forEach(obj => {
innerHTML += ' - ' + obj.nome;
});
tables.innerHTML = innerHTML;
erro = document.getElementById("erro");
erro.innerHTML = "";
} else {
let tables = document.getElementById("listareceitas");
tables.innerHTML = " - ";
erro = document.getElementById("erro");
erro.innerHTML = "Erro na consulta dos dados";
}
}