Antes de empezar

1

Pasos para aprender Java Spring

2

ÂżJava sigue siendo gratuito?

3

InstalaciĂłn de ambiente de desarrollo: Linux Ubuntu

4

InstalaciĂłn de ambiente de desarrollo: macOS

5

InstalaciĂłn de ambiente de desarrollo: Windows

IntroducciĂłn a Spring boot

6

¿Qué es y qué usaremos de Spring?

7

Conocer qué es una aplicación autocontenida

8

Crear nuestra aplicaciĂłn con Spring Initializr

9

Hola mundo con Spring Boot

10

Configurar Spring Boot

11

Crear la estructura del proyecto

Spring Data

12

¿Qué es JPA?

13

Conocer qué es Spring Data

14

Conectar la base de datos a nuestra aplicaciĂłn

15

Mapear las tablas como clases

16

Crear Entity cuando su clave primaria es compuesta

17

Mapear relaciones entre clases

18

Usar la interface CrudRepository

19

Query Methods

Construyendo nuestra API

20

Implementar la anotaciĂłn @Repository

21

¿Qué es el patrón Data Mapper y qué resuelve?

22

Orientar nuestra API al dominio con MapStruct

23

Orientar nuestro repositorio a términos del dominio

24

InyecciĂłn de dependencias

25

Implementar la anotaciĂłn @Service

26

Implementar la anotaciĂłn @RestController

27

Exponer nuestra API

Mejorando nuestra API

28

Controlar las respuestas HTTP

29

Crear el dominio de compras

30

Mapear el dominio de compras

31

Crear el repositorio de compras

32

Probando nuestros servicios de compras

33

Documentar nuestra API con Swagger

Spring Security

34

Configurar la seguridad de nuestra API con Spring Security

35

Generar un JWT

36

AutenticaciĂłn con JWT

37

AutorizaciĂłn con JWT

Despliegue de nuestra aplicaciĂłn

38

Desplegar nuestra API desde la ventana de comandos

39

Desplegar nuestra base de datos con Heroku

40

Desplegar nuestra API con Heroku

41

Conclusiones y despedida del curso

AĂșn no tienes acceso a esta clase

Crea una cuenta y continĂșa viendo este curso

Curso de Java Spring

Curso de Java Spring

Alejandro RamĂ­rez

Alejandro RamĂ­rez

Exponer nuestra API

27/41
Recursos

Aportes 44

Preguntas 21

Ordenar por:

ÂżQuieres ver mĂĄs aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesiĂłn.

Para mi asi deberian de quedar los servicios.

Se me ocurrio el update de la siguiente forma, pero pienso que debe haber una mejor manera de hacerlo

package com.platzi.market.domain.service;

import com.platzi.market.domain.Product;
import com.platzi.market.domain.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public List<Product> getAll(){
        return productRepository.getAll();
    }

    public Optional<Product> getProduct(long productId){
        return productRepository.getProduct(productId);
    }

    public Optional<List<Product>> getByCategory (long categoryId){
        return productRepository.getByIdCategory(categoryId);
    }

    public Optional<List<Product>> getScarseProducts (int quantity){
        return  productRepository.getScarseProduct(quantity);
    }

    public Product save (Product product){
        return productRepository.save(product);
    }

    public boolean delete (long productId){
         return getProduct(productId).map(product -> {
             productRepository.delete(productId);
            return true;
         }).orElse(false);
    }


    public void update (long productId , Product product){
         Product product1 = getProduct(productId).get();
         product1.setName(product.getName());
         product1.setCategory(product.getCategory());
         product1.setActive(product.isActive());
         product1.setPrice(product.getPrice());
         product1.setStock(product.getStock());
         save(product1);
    }
package com.platzi.market.web.controller;

import com.platzi.market.domain.Product;
import com.platzi.market.domain.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/products")
public class ProductController {

    @Autowired
    private ProductService productService;

    @GetMapping("/all")
    public List<Product>getAll(){
        return productService.getAll();
    }

    @GetMapping("/{id}")
    public Optional<Product> getProducto(@PathVariable("id") long productId){
        return productService.getProduct(productId);
    }

    @GetMapping("/category/{categoryId}")
    public Optional<List<Product>> getByCategory(@PathVariable("categoryId") long categoryId){
        return  productService.getByCategory(categoryId);
    }

    @PostMapping("/save")
    public Product save(@RequestBody  Product product){
        return productService.save(product);
    }

    @PutMapping("/{id}")
    public void update (@PathVariable("id") long productId, @RequestBody Product product){
        productService.update(productId, product);
    }

    @DeleteMapping("/delete/{id}")
    public boolean delete(@PathVariable("id") long productId){
        return productService.delete(productId);
    }


}

Las rutas me dan 404, aunque tengo todo aparentemente bien configurado, incluso descargando el proyecto desde acĂĄ me dan 404. He revisado el context y estĂĄ correcto. Que podrĂ­a ser?

Hola, encontré la razón para el error 404, en mi caso se debe a que añadí un paråmetro en la anotación de la clase del método main:

@SpringBootApplication(scanBasePackages={"com.platzi.market.persistence.mapper.ProductMapper"})

Debe dejarse sĂłlo la anotaciĂłn @SpringBootApplication y solucionar el tema del Mapper diferente.
Al parecer el plugin tiene inconvenientes en eclipse y por eso no genera el Impl de cada mapper.
Esto lo solucioné con dos cosas en eclipse:
1. Clic derecho sobre el proyecto -> propiedades -> Java Compiler -> Annotation Processing -> 
	Se debe checkear Enable project specific settings 
2. Clic derecho sobre el proyecto -> propiedades -> Java Compiler -> Annotation Processing -> Factory Path ->   
	Se debe checkear Enable project specific settings
	-> Add External Jar -> AquĂ­ buscar el jar del plugin es una ruta similar:
C:\Users\pepito\.gradle\caches\modules-2\files-2.1\org.mapstruct\mapstruct-processor\1.4.2.Final\e55bd90d51cddd638c07d5bd89fc7535d4e3d069\mapstruct-processor-1.4.2.Final

Ahora Aplicar y Cerrar

Créditos: [](https://stackoverflow.com/questions/45518161/how-to-get-eclipse-to-generate-mapstruct-mappers-using-gradle)

Profe segun las buenas practicas para exponer servicio NO se debe poner delete ni save como parte de la url ya que estos son parte del verbo del http?
Otro punto porque no se usa LOMBOCK para los setter y getters?

Si quieren ver todo el log de su aplicaciĂłn agregen en application.properties

#log
logging.file.path=C:/spring-boot-app.log```

ÂżEl nuevo reto seria modificar un producto?

Hola a todos!
Por favor podrĂ­an ayudarme a entender porque al final de la peticiĂłn POST (min 7:42) category estĂĄ en null.

Que emoción ver que todo funciona a la perfección 😄

Siempre disfruto la manera en como explicas Alejandro un abrazo, genial esta clase.

Genial!!!

AsĂ­ quedĂł mi @PutMapping que opinan?

    @PutMapping("/{productId}")
    public ResponseEntity<Product> updateProduct(@PathVariable("productId") Integer productId,
                                                 @RequestBody Product product){
        product.setProductId(productId);
        return new ResponseEntity<>(this.productService.save(product), HttpStatus.OK);

    }

En mi caso me daba 404 porque se me olvidĂł recompilar el API đŸ€Ł. Por si a alguno le pasa.

  • Estoy haciendo un proyecto de medicina y asĂ­ de grande me quedĂ­ el JSON de la historia clinica.
    {
    “clinicalHistoryId”: 1,
    “reasonConsultation”: “dolor”,
    “currentIllness”: “migraña”,
    “analysis”: “migraña que puede ser tratada facilmente”,
    “diagnostics”: “no es grave”,
    “clinicalHistoryDate”: “2021-08-28T17:03:05”,
    “physicalExamId”: 1,
    “managementPlanId”: 1,
    “patientId”: 1,
    “neurologicalExamId”: 1,
    “systemReviewId”: 1,
    “backgroundId”: 1,
    “managementPlan”: {
    “mpId”: 0,
    “description”: null,
    “evolutionId”: null
    },
    • “neurologicalExam”: {
      “neurologicalExamId”: 1,
      “mental”: “estable”,
      “cranialNerves”: “tamaño natural”,
      “spinalMotor”: “en perfecto estado”,
      “spinalSesitive”: “normal”,
      “reflexes”: “bajos”,
      “coordination”: “buena”,
      “march”: “positiva”
      },
      “systemReview”: {
      “srId”: 1,
      “neuropsychiatric”: “Estado aceptable”,
      “mammary”: “No aplica”,
      “generalSymptoms”: “dolor de cabeza”,
      “headSenses”: “estables”,
      “lymphoreticular”: “bien”,
      “cardiopulmonary”: “debil”,
      “gastrointestinal”: “estreñimiento”,
      “psychogenic”: “bien”,
      “gynecologicalUrinary”: “no hay problema”,
      “skeletalMuscle”: “fuerte”,
      “pierlAppendages”: “libre de imperfecciones”,
      “endocrine”: “todo funcionando bien”,
      “venereal”: “bien”
      },
      “background”: {
      “backgroundId”: 1,
      “psychosocial”: “se le dificulta”,
      “relatives”: “ninguno”,
      “surgical”: “apendicitis”,
      “hospitable”: “3 meses en la UCI”,
      “pathological”: “anemia”,
      “pharmacological”: “omeprazol”,
      “toxicAllergies”: “claustrofobia”,
      “traumatic”: “no aplica”,
      “obstetricGynecology”: “ninguno”,
      “immunological”: “ninguno”,
      “psychiatric”: “ninguno”
      },
      “patient”: {
      “patientId”: 1,
      “occupation”: “celador”,
      “religion”: “católico”,
      “race”: “no aplica”,
      “laterality”: “diestro”,
      “informant”: “Diana”,
      “relationship”: “esposa”,
      “rh”: “A+”,
      “reliability”: “alta”,
      “room”: “20”,
      “admissionDate”: “2021-08-28T16:36:30”,
      “hpeId”: 3,
      “maritalStatusId”: 2,
      “scholarshipId”: 3,
      “personId”: 21190080,
      “placeId”: 0,
      “person”: {
      “personId”: 21190080,
      “firstName”: “Alejandro”,
      “lastName”: “Buitrago Rojas”,
      “age”: “30”,
      “sex”: “hombre”,
      “birthDate”: “1991-02-21”
      },
      • “place”: {
        “placeId”: 3,
        “placeBirth”: “Cumaral”,
        “placeResidence”: “Guaviare”,
        “placeOrigin”: “Guamal”
        },
        “scholarship”: {
        “scholarshipId”: 3,
        “scholarshipName”: “pregrado”
        },
        “maritalStatus”: {
        “maritalStatusId”: 2,
        “maritalStatusName”: “casado(a)”
        },
        “hpe”: {
        “hpeId”: 3,
        “hpsName”: “Medimas”
        }
        },
        “physicalExam”: {
        “physicalExamId”: 1,
        “chest”: “buen estado”,
        “abdomen”: “perfecto estado”,
        “extremities”: “estado regular”,
        “column”: “mal estado”
        }
        }

‎ ‏‏‎

Buen dĂ­a me podrĂ­an ayudar a mi me muestra el siguiente mensaje de error yo estoy trabajando con el ide Spring tool suite.


APPLICATION FAILED TO START


Description:

Field mapper in com.platzi.market.persistence.ProductoRepository required a bean of type ‘com.platzi.market.persistence.mapper.ProductMapper’ 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.platzi.market.persistence.mapper.ProductMapper’ in your configuration.

como se resuelve este error despues de intentar hacer la peticion?
Caused by: org.postgresql.util.PSQLException: ERROR: no existe la relaciïżœn ïżœcategoriaïżœ

De a poco y con paciencia, voy aprendiendo y avanzando en el curso. Me gusta mucho Spring. Algunos errores los puedo solucionar y en otros, me salva el genio de Alejandro. En este vídeo quedé en la parte del getAll(), en la primer petición digamos. En intellij IDEA no me arroja error ni nada, el problema es cuando pongo el sitio web tal cual como se ve en el vídeo, me arroja este error .

He tenido que agregar esto a la anotation SpringBootApplication ya que de lo contrario me daba este error

Hola yo tengo el problema que al exponer mi API me carga sin ningun error. Pero a la hora de hacer las peticiones desde el navegador o desde postman no me carga nada.

Comparto mi repositorio AQUI

Y esto me sale en Postman

tenia el error 404 y el tema del error Bean

lo solucione agregando lo siguiente en el pom

<properties>
		<java.version>17</java.version>
		<org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
	</properties>
......


<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct</artifactId>
			<version>1.4.2.Final</version>
		</dependency>
........

<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.1</version>
				<configuration>
					<source>17</source> <!-- depending on your project -->
					<target>17</target> <!-- depending on your project -->
					<annotationProcessorPaths>
						<path>
							<groupId>org.mapstruct</groupId>
							<artifactId>mapstruct-processor</artifactId>
							<version>${org.mapstruct.version}</version>
						</path>
						<!-- other annotation processors -->
					</annotationProcessorPaths>
				</configuration>
			</plugin>

luego click derecho encima del proyecto -> Rebuild module

En base a mi error si les aparece un error de llave forĂĄnea revisen que tengan @RequestBody colocado en el save

Buen día comunidad, primero agradecer a todos por sus comentarios y al profesor por su gran forma de enseñar.

Al igual que muchos me tope con el problema de:

The injection point has the following annotations:

@org.springframework.beans.factory.annotation.Autowired(required=true)
Y si, el problema se da cuando estamos usando nuestro IDE como ejecutor (no todos) en mi caso VSC, pero la mejor forma de seguir adelante es compilar y levantar la aplicaciĂłn por terminal

.\gradlew bootrun

En caso de que salga error como;

Unknown property “productos” in result type com.platzi.market.persistence.entity.Categoria. Did you mean “estado”?”

Debes generar los get y set faltantes en Categoria y Producto

para los que tenga el error 404 verifiquen su ruta en mi caso no me agarraba lo que es el /platzi-market/api que esta en propertys

Hola a todos.

El GET de /products/all me devuelve el siguiente error. Espero que alguien pueda ayudarme.

{
    "timestamp": "2021-04-15T09:01:53.819+00:00",
    "status": 500,
    "error": "Internal Server Error",
    "trace": "org.springframework.dao.DataIntegrityViolationException: could not execute query; SQL [select producto0_.id_producto as id_produ1_4_, producto0_.cantidad_stock as cantidad2_4_, producto0_.id_categoria as id_categ5_4_, producto0_.codigo_barras as codigo_b3_4_, producto0_.estado as estado4_4_, producto0_.nombre as nombre6_4_, producto0_.precio_venta as precio_v7_4_ from productos producto0_]; nested exception is org.hibernate.exception.DataException: could not execute query\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:280)\r\n\tat org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:233)\r\n\tat org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)\r\n\tat org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)\r\n\tat org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)\r\n\tat com.sun.proxy.$Proxy88.findAll(Unknown Source)\r\n\tat com.mariomonzon.techmarket.persistence.ProductoRepository.getAll(ProductoRepository.java:25)\r\n\tat com.mariomonzon.techmarket.persistence.ProductoRepository$$FastClassBySpringCGLIB$$400176ab.invoke(<generated>)\r\n\tat org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)\r\n\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:779)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)\r\n\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:750)\r\n\tat org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:692)\r\n\tat com.mariomonzon.techmarket.persistence.ProductoRepository$$EnhancerBySpringCGLIB$$90edcba1.getAll(<generated>)\r\n\tat com.mariomonzon.techmarket.domain.service.ProductService.getAll(ProductService.java:18)\r\n\tat com.mariomonzon.techmarket.web.controller.ProductController.getAll(ProductController.java:22)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.lang.reflect.Method.invoke(Method.java:498)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:197)\r\n\tat org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:141)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:894)\r\n\tat org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)\r\n\tat org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1060)\r\n\tat org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:962)\r\n\tat org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)\r\n\tat org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:626)\r\n\tat org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)\r\n\tat javax.servlet.http.HttpServlet.service(HttpServlet.java:733)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)\r\n\tat org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)\r\n\tat org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)\r\n\tat org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)\r\n\tat org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)\r\n\tat org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)\r\n\tat org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)\r\n\tat org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)\r\n\tat org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)\r\n\tat org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:357)\r\n\tat org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)\r\n\tat org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)\r\n\tat org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893)\r\n\tat org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1707)\r\n\tat org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)\r\n\tat java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)\r\n\tat java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)\r\n\tat org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)\r\n\tat java.lang.Thread.run(Thread.java:748)\r\nCaused by: org.hibernate.exception.DataException: could not execute query\r\n\tat org.hibernate.exception.internal.SQLStateConversionDelegate.convert(SQLStateConversionDelegate.java:115)\r\n\tat org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42)\r\n\tat org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113)\r\n\tat org.hibernate.loader.Loader.doList(Loader.java:2852)\r\n\tat org.hibernate.loader.Loader.doList(Loader.java:2831)\r\n\tat org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2663)\r\n\tat org.hibernate.loader.Loader.list(Loader.java:2658)\r\n\tat org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:506)\r\n\tat org.hibernate.hql.internal.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:400)\r\n\tat org.hibernate.engine.query.spi.HQLQueryPlan.performList(HQLQueryPlan.java:219)\r\n\tat org.hibernate.internal.SessionImpl.list(SessionImpl.java:1414)\r\n\tat org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1625)\r\n\tat org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1593)\r\n\tat org.hibernate.query.Query.getResultList(Query.java:165)\r\n\tat org.hibernate.query.criteria.internal.compile.CriteriaQueryTypeQueryAdapter.getResultList(CriteriaQueryTypeQueryAdapter.java:76)\r\n\tat org.springframework.data.jpa.repository.support.SimpleJpaRepository.findAll(SimpleJpaRepository.java:356)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\r\n\tat sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)\r\n\tat sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\r\n\tat java.lang.reflect.Method.invoke(Method.java:498)\r\n\tat org.springframework.data.repository.core.support.RepositoryMethodInvoker$RepositoryFragmentMethodInvoker.lambda$new$0(RepositoryMethodInvoker.java:289)\r\n\tat org.springframework.data.repository.core.support.RepositoryMethodInvoker.doInvoke(RepositoryMethodInvoker.java:137)\r\n\tat org.springframework.data.repository.core.support.RepositoryMethodInvoker.invoke(RepositoryMethodInvoker.java:121)\r\n\tat org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:524)\r\n\tat org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:285)\r\n\tat org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:531)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.doInvoke(QueryExecutorMethodInterceptor.java:156)\r\n\tat org.springframework.data.repository.core.support.QueryExecutorMethodInterceptor.invoke(QueryExecutorMethodInterceptor.java:131)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123)\r\n\tat org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388)\r\n\tat org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)\r\n\tat org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)\r\n\tat org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:137)\r\n\t... 70 more\r\nCaused by: org.postgresql.util.PSQLException: Bad value for type int : 7029 A42 23\r\n\tat org.postgresql.jdbc.PgResultSet.toInt(PgResultSet.java:3014)\r\n\tat org.postgresql.jdbc.PgResultSet.getInt(PgResultSet.java:2188)\r\n\tat org.postgresql.jdbc.PgResultSet.getInt(PgResultSet.java:2626)\r\n\tat com.zaxxer.hikari.pool.HikariProxyResultSet.getInt(HikariProxyResultSet.java)\r\n\tat org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$2.doExtract(IntegerTypeDescriptor.java:62)\r\n\tat org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47)\r\n\tat org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257)\r\n\tat org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253)\r\n\tat org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243)\r\n\tat org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:329)\r\n\tat org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:3130)\r\n\tat org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1869)\r\n\tat org.hibernate.loader.Loader.hydrateEntityState(Loader.java:1797)\r\n\tat org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1770)\r\n\tat org.hibernate.loader.Loader.getRow(Loader.java:1622)\r\n\tat org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:740)\r\n\tat org.hibernate.loader.Loader.getRowsFromResultSet(Loader.java:1039)\r\n\tat org.hibernate.loader.Loader.processResultSet(Loader.java:990)\r\n\tat org.hibernate.loader.Loader.doQuery(Loader.java:959)\r\n\tat org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:349)\r\n\tat org.hibernate.loader.Loader.doList(Loader.java:2849)\r\n\t... 101 more\r\n",
    "message": "could not execute query; SQL [select producto0_.id_producto as id_produ1_4_, producto0_.cantidad_stock as cantidad2_4_, producto0_.id_categoria as id_categ5_4_, producto0_.codigo_barras as codigo_b3_4_, producto0_.estado as estado4_4_, producto0_.nombre as nombre6_4_, producto0_.precio_venta as precio_v7_4_ from productos producto0_]; nested exception is org.hibernate.exception.DataException: could not execute query",
    "path": "/products/all"
}

Hola, este es mi update:

@RestController
@RequestMapping("/products")
public class ProductController {
    private ProductService productService;

    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

   // Methods

    @PutMapping
    public Product update(@RequestBody Product product) {
        return productService.update(product);
    }
}
@Service
public class ProductService {
    private ProductRepository productRepository;

    @Autowired
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    // Methods

    public Product update(Product product) {
        return getProduct(product.getProductId()).map(productToUpdate -> {
            productToUpdate.setName(product.getName());
            productToUpdate.setCategoryId(product.getCategoryId());
            productToUpdate.setPrice(product.getPrice());
            productToUpdate.setStock(product.getStock());
            productToUpdate.setActive(product.isActive());
            return save(productToUpdate);
        }).orElse(null);
    }
}

Buena explicación para exponer los endpoints, pero mala implementación de nomenclatura en las URI’s, sería muy bueno que sigan el modelo de madurez de Richardson.

Tengo este pequeño problema al mandar la peticion

for servlet [dispatcherServlet] in context with path [/path/api] threw exception [Request processing failed; nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: For input string: “Frutas y verduras”; nested exception is java.lang.NumberFormatException: For input string: “Frutas y verduras”] with root cause

![](

En mi caso no funciona que se le cambie el nombre en la etiqueta @GetMapping, lo que me funcionĂł fue dejar el mismo nombe en ambas etiquetas.

@GetMapping("/{productId}")
public Optional<Product> getProduct(@PathVariable(“productId”) int productId){
return productService.getProduct(productId);
}

para el category, todo me arroja 0 para los valores del objeto, a nivel campo del producto si me ejecuta correctamente, alguna idea?

En elipse pase un buen tiempo tratando de solucionar el problema con MAPPER, por alguna razĂłn no esta descargando bien la librerĂ­a. La soluciĂłn rĂĄpida fue cambiar de editor a IntelliJ

Cuando ejecuto tu proyecto
funciona

Cuando ejecuto el mio
 me sale el siguiente error:

Execution failed for task ‘:AndheurisMarketApplication.main()’.

Process ‘command ‘C:/Program Files/Java/jdk-14.0.2/bin/java.exe’’ finished with non-zero exit value 1

  • Try:
    Run with --stacktrace option to get the stack trace. Run with --scan to get full insights.

como puede fallar java si corre con tu project y no con el mio?..

Hola, este es mi update:

@RestController
@RequestMapping("/products")
public class ProductController {
    private ProductService productService;

    @Autowired
    public ProductController(ProductService productService) {
        this.productService = productService;
    }

   // MĂ©todos

    @PutMapping
    public Product update(@RequestBody Product product) {
        return productService.update(product);
    }
}
@Service
public class ProductService {
    private ProductRepository productRepository;

    @Autowired
    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    // Methods

    public Product update(Product product) {
        return getProduct(product.getProductId()).map(productToUpdate -> {
            productToUpdate.setName(product.getName());
            productToUpdate.setCategoryId(product.getCategoryId());
            productToUpdate.setPrice(product.getPrice());
            productToUpdate.setStock(product.getStock());
            productToUpdate.setActive(product.isActive());
            return save(productToUpdate);
        }).orElse(null);
    }
}

Hola, me enfrente a dos problemas. El primero al momento de querer guardar el producto en el método save me arrojaba el error 405 method not allowed. Una vez solucionado me arrojaba el error 415 Unsupported Media Type.
Para solucionar el primer error, observe que a la URL no le habĂ­a quitado la palabra category.
Con error: platzi-market/api/products/category/save
Sin error: platzi-market/api/products/save
Para resolver el error 415, en el Postman agrege el siguiente header KEY Content-Type VALUE application/json dentro del menĂș Heades.

Metodo que se me ocurrio en DomainProductService para actualizar un producto. No se que opinen que podria mejorarle ?

public DomainProduct update(DomainProduct updateProduct) {
		return getById(updateProduct.getCode()).map(product -> {
			save(updateProduct);
			return updateProduct;
		}).orElse(new DomainProduct());
	}

Si les llega a salir un error 500 al momento de hacer un save, revisen que estén bien puestos los @InheritInverseConfiguration en las interfaces de mapper

Considero que no es necesario crear un endpoint solamente para obtener los productos de una categorĂ­a. La soluciĂłn que prefiero es pasar el categoryId como un Optional QueryParam al endpoint que ya retorna una lista de productos. Y manejar la respuesta dependiendo de si este parĂĄmetro estĂĄ o no presente.

@GetMapping
    public List<Product> getAll(@RequestParam(name = "category") Optional<Integer> categoryId) {
        if (categoryId.isPresent())
            return productService.getByCategory(categoryId.get()).orElseGet(() -> null);
        return this.productService.getAll();
    }

    @PostMapping
    public Product save(@RequestBody Product product) {
        return this.productService.save(product);
    }

    @GetMapping("/{id}")
    public Optional<Product> get(@PathVariable("id") int id) {
        return this.productService.get(id);
    }

    @DeleteMapping("/{id}")
    public boolean delete(@PathVariable("id") int id) {
        return productService.delete(id);
    }```

Wooow! Maestrazo!!!
a mi me mandaba error 404 porque el nombrede “platzi-market” lo cambiĂ© desde un inicio por otro, al darme cuenta lo corrĂ­ con el nombre correcto y funcionĂł sin problema 😉
Gracias profesor por compartir su conocimiento

Para todos los que nos han salido errors ojala esto sirva de ayuda :

  1. Checar que en domain -> service-> Category tenga dentro sus geter y setteer

public String getCategory() {
return category;
}

public void setCategory(String category) {
    this.category = category;
}
  1. que la interface ProductoCrudRepository este tal cual esta en el git o si no como les dejo

public interface ProductoCrudRepository extends CrudRepository<Producto, Integer> {

public List<Producto> findByIdCategoriaOrderByNombreAsc(int idCategoria);
Optional<List<Producto>> findByCantidadStockLessThanAndEstado(int cantidadStock, boolean estado);
}

Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type ‘java.lang.String’ to required type ‘int’; nested exception is java.lang.NumberFormatException: For input string: “save”]

me podrĂ­an ayudar con este error?
me sale cuando uso el mĂ©todo “save”.

Una alternativa para obtener un producto por id es, usando @RequestBody el cual nos va a permitir usar como parĂĄmetro objetos json. Nos ayudarĂĄ a no pasar parĂĄmetros por url.

todo bien pero cuando intento hacer un save o un delete me aparece esto
.

Para poder usar los datos de la API despuĂ©s por medio de Ajax es necesario devolver los datos de la API a travĂ©s de un HashMap con un nombre “x” de la lista y la List<Product> en vez de solo la List<Product>?