{"id":237,"date":"2018-05-30T17:08:43","date_gmt":"2018-05-30T17:08:43","guid":{"rendered":"http:\/\/www.canchito-dev.com\/public\/blog\/?p=237"},"modified":"2021-05-02T13:48:23","modified_gmt":"2021-05-02T13:48:23","slug":"rest-api-with-spring-jpa-criteria","status":"publish","type":"post","link":"http:\/\/www.canchito-dev.com\/public\/blog\/2018\/05\/30\/rest-api-with-spring-jpa-criteria\/","title":{"rendered":"REST API with Spring JPA Criteria"},"content":{"rendered":"<p style=\"text-align: justify;\"><div class=\"perfect-pullquote vcard pullquote-align-full pullquote-border-placement-left\" style=\"font-size:14px !important;\"><blockquote><p style=\"font-size:14px !important;\"><\/p>\n<p style=\"text-align: justify;\">In this guide, you will learn how to set up and build a simple REST API with Spring, that provides CRUD operations for entries that are saved into a database. In addition, you will learn how use JPA&#8217;s criteria API to perform filtered searches for records.<\/p>\n<p style=\"text-align: justify;\"><\/p><\/blockquote><\/div><\/p>\n<div>\n  <a class=\"donate-with-crypto\"\n     href=\"https:\/\/commerce.coinbase.com\/checkout\/faf64f90-2e80-46ee-aeba-0fde14cbeb46\"><br \/>\n    Buy Me a Coffee<br \/>\n  <\/a><br \/>\n  <script src=\"https:\/\/commerce.coinbase.com\/v1\/checkout.js?version=201807\">\n  <\/script>\n<\/div>\n\n<h1 style=\"text-align: justify;\">Contribute Code<\/h1>\n<p style=\"text-align: justify;\">If you would like to become an active contributor to this project please follow theses simple steps:<\/p>\n<ol>\n<li style=\"text-align: justify;\">Fork it<\/li>\n<li style=\"text-align: justify;\">Create your feature branch<\/li>\n<li style=\"text-align: justify;\">Commit your changes<\/li>\n<li style=\"text-align: justify;\">Push to the branch<\/li>\n<li style=\"text-align: justify;\">Create new Pull Request<\/li>\n<\/ol>\n<p style=\"text-align: justify;\"><strong>Source code<\/strong> can be downloaded from <a href=\"https:\/\/github.com\/canchito-dev\/rest-api-with-jpa-criteria\" target=\"_blank\" rel=\"noopener noreferrer\">github<\/a>.<\/p>\n<h1 class=\"sect1\" style=\"text-align: justify;\">What you\u2019ll need<\/h1>\n<ul style=\"text-align: justify;\">\n<li>About 30\u00a0minutes<\/li>\n<li>A favorite IDE or\u00a0Spring Tool Suite&#x2122; already install<\/li>\n<li><a href=\"http:\/\/www.oracle.com\/technetwork\/java\/javase\/downloads\/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">JDK 6<\/a> or later<\/li>\n<\/ul>\n<h1>Introduction<\/h1>\n<p style=\"text-align: justify;\">The JPA Criteria API provides an alternative way for defining dynamic JPA queries. This is very useful for searching\/filtering data, where a simple search is not enough.<\/p>\n<p style=\"text-align: justify;\">JPA criteria queries are defined by instantiation of Java objects that represent query elements.<\/p>\n<p style=\"text-align: justify;\">A major advantage of using the criteria API is that errors can be detected earlier, during compilation rather than at runtime.<\/p>\n<p style=\"text-align: justify;\">To show you how the JPA criteria API works, we have created a very simple REST API, with a very simple search functionality for restricting the search results.<\/p>\n<p style=\"text-align: justify;\">For our purposes, lets assume we have a list of authors, and a list of books written by those authors.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" data-attachment-id=\"238\" data-permalink=\"http:\/\/www.canchito-dev.com\/public\/blog\/2018\/05\/30\/rest-api-with-spring-jpa-criteria\/rest-api-with-spring-jpa-criteria-table\/\" data-orig-file=\"http:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2018\/05\/rest-api-with-spring-jpa-criteria-table.png\" data-orig-size=\"549,275\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"rest-api-with-spring-jpa-criteria-table\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"http:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2018\/05\/rest-api-with-spring-jpa-criteria-table.png\" class=\"aligncenter size-full wp-image-238\" src=\"http:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2018\/05\/rest-api-with-spring-jpa-criteria-table.png\" alt=\"\" width=\"549\" height=\"275\" srcset=\"http:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2018\/05\/rest-api-with-spring-jpa-criteria-table.png 549w, http:\/\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2018\/05\/rest-api-with-spring-jpa-criteria-table-300x150.png 300w\" sizes=\"auto, (max-width: 549px) 100vw, 549px\" \/><\/p>\n<p>If you would like to know the REST API was built, please refer to our previous <a href=\"http:\/\/www.canchito-dev.com\/public\/blog\/2017\/04\/22\/build-a-rest-api-with-spring\/\">article<\/a> and its related <a href=\"https:\/\/github.com\/canchito-dev\/build-a-rest-api-with-spring\">GitHub<\/a> project.<\/p>\n<p>We will basically focus on the changes introduced in this article and how it uses JPA criteria to filter results.<\/p>\n<h1>Author and Books Entity<\/h1>\n<p>First, let\u2019s have a look at the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Author<\/code> entities.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Entity\r\npublic class Author {\r\n  \r\n  @Id\r\n  @GeneratedValue(strategy = GenerationType.AUTO)\r\n  @Column(name = \"id_author\", unique = true, nullable = false, length = 255)\r\n  private Long authorId;\r\n  \r\n  @Column(name = \"first_name\", nullable = false, length = 60)\r\n  private String firstName;\r\n  \r\n  @Column(name = \"last_name\", nullable = false, length = 60)\r\n  private String lastName;\r\n  \r\n  @Column(name = \"telephone\", nullable = false, length = 60)\r\n  private String telephone;\r\n  \r\n  @Column(name = \"mail\", nullable = false, length = 60)\r\n  private String mail;\r\n  \r\n  @OneToMany(fetch = FetchType.LAZY, mappedBy = \"author\", cascade = CascadeType.ALL)\r\n  private List&lt;Books&gt; books = new ArrayList&lt;Books&gt;();\r\n  \r\n  public Author() {}\r\n\r\n  public Author(Long authorId, String firstName, String lastName, String telephone, String mail, List&lt;Books&gt; books) {\r\n    this.authorId = authorId;\r\n    this.firstName = firstName;\r\n    this.lastName = lastName;\r\n    this.telephone = telephone;\r\n    this.mail = mail;\r\n    this.books = books;\r\n  }\r\n  \r\n  \/\/Getters and setters removed for simplicity\r\n}<\/pre>\n<p>And now the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Books<\/code> entity.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Entity\r\npublic class Books {\r\n  \r\n  @Id\r\n  @GeneratedValue(strategy = GenerationType.AUTO)\r\n  @Column(name = \"id_book\", unique = true, nullable = false, length = 255)\r\n  private Long bookId;\r\n  \r\n  @Column(name = \"title\", nullable = false, length = 60)\r\n  private String title;\r\n  \r\n  @Column(name = \"year\", nullable = false, length = 4)\r\n  private Integer year;\r\n  \r\n  @Column(name = \"price\", nullable = false, length = 10)\r\n  private String price;\r\n  \r\n  @ManyToOne(fetch = FetchType.LAZY)\r\n    @JoinColumn(name = \"id_author\", nullable = false)\r\n  private Author author;\r\n  \r\n  public Books() {}\r\n\r\n  public Books(Long bookId, String title, Integer year, String price, Author author) {\r\n    this.bookId = bookId;\r\n    this.title = title;\r\n    this.year = year;\r\n    this.price = price;\r\n    this.author = author;\r\n  }\r\n  \r\n  \/\/Getters and setters removed for simplicity\r\n}<\/pre>\n<p>As you may have noticed, we have created the relationship between both entities by adding the annotations <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@OneToMany<\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@ManyToOne<\/code>, and of course the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@JoinColumn<\/code>. Here a brief explanation of each annotation:<\/p>\n<ul>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@OneToMany<\/code>: Defines a many-valued association with one-to-many multiplicity.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@ManyToOne<\/code>: Defines a single-valued association to another entity class that has many-to-one multiplicity.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@JoinColumn<\/code>: Specifies a column for joining an entity association or element collection.<\/li>\n<\/ul>\n<h1>Using the CriteriaBuilder<\/h1>\n<p>The main factory of the criteria API and all its elements, is the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CriteriaBuilder<\/code>. In other words, the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CriteriaBuilder<\/code> is used to construct criteria queries, compound selections, expressions, predicates, orderings, to mention some.<\/p>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">CriteriaBuilder <\/code>interface defines functionality that is specific to top-level queries.<\/p>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Root<\/code> type is the from clause. Please notice that query roots always reference entities.<\/p>\n<p>And finally, we have the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Join<\/code>. A <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Join<\/code> to an entity, embeddable, or basic type.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">public Page&lt;Author&gt; search(List&lt;SearchCriteria&gt; paramsAuthor, List&lt;SearchCriteria&gt; paramsBooks, Pageable pageable) {\r\n  CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();\r\n        CriteriaQuery&lt;Author&gt; criteriaQuery = criteriaBuilder.createQuery(Author.class);\r\n        Root&lt;Author&gt; author = criteriaQuery.from(Author.class);\r\n    \tJoin&lt;Author, Books&gt; books = author.join(\"books\", JoinType.INNER);\r\n \r\n        Predicate predicate = this.predicateRootBuilder(criteriaBuilder, paramsAuthor, author);\r\n        \r\n        if(!paramsBooks.isEmpty())\r\n        \tpredicate = this.predicateJoinBuilder(criteriaBuilder, paramsBooks, books);\r\n        \r\n        Sort sort = pageable.isPaged() ? pageable.getSort() : Sort.unsorted();\r\n        \r\n        if (sort.isSorted())\r\n        \u00a0\u00a0\u00a0criteriaQuery.orderBy(toOrders(sort, author, criteriaBuilder));\r\n        \r\n        criteriaQuery.distinct(true);\r\n        \r\n        criteriaQuery.where(predicate);\r\n        \r\n        TypedQuery&lt;Author&gt; typedQuery = entityManager.createQuery(criteriaQuery);\r\n        \r\n        if(pageable == null)\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return new PageImpl&lt;Author&gt;(typedQuery.getResultList());\r\n        else {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0Long total = (long) typedQuery.getResultList().size();\r\n      \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Sets the offset position in the result set to start pagination\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0typedQuery.setFirstResult((int) pageable.getOffset());\r\n      \r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/ Sets the maximum number of entities that should be included in the page\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0typedQuery.setMaxResults(pageable.getPageSize());\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0List&lt;Author&gt; content = total &gt; pageable.getOffset() ? typedQuery.getResultList() : Collections.&lt;Author&gt; emptyList();\r\n\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return new PageImpl&lt;Author&gt;(content, pageable, total);\r\n        }\r\n}<\/pre>\n<p>To filter the results, we use a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Predicate<\/code>, which can be a simple or compound predicate: a conjunction or disjunction of restrictions. A simple predicate is considered to be a conjunction with a single conjunct.<\/p>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Predicate<\/code>, uses a very simple class to create the constrains for both, the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Author<\/code> and <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">Books<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">public class SearchCriteria {\r\n  \r\n    private String key;\r\n    private String operation;\r\n    private Object value;\r\n    \r\n    public SearchCriteria() {}\r\n    \r\n    public SearchCriteria(String key, String operation, Object value) {\r\n        super();\r\n        this.key = key;\r\n        this.operation = operation;\r\n        this.value = value;\r\n    }\r\n  \r\n    \/\/Getters and setters removed for simplicity\r\n}<\/pre>\n<p>The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">SearchCriteria<\/code> implementation holds our Query parameters:<\/p>\n<ul>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">key<\/code>: used to hold field name \u2013 for example: firstName, age, \u2026 etc.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">operation<\/code>: used to hold the operation \u2013 for example: Equality, less than, \u2026 etc.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">value<\/code>: used to hold the field value \u2013 for example: john, 25, \u2026 etc.<\/li>\n<\/ul>\n<p>The list of Query parameters is filled with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">SearchCriteria<\/code> implementations, which are added by the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">setSearchCriteria<\/code> function.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">private List&lt;SearchCriteria&gt; setSearchCriteria(String search) {\r\n        List&lt;SearchCriteria&gt; params = new ArrayList&lt;SearchCriteria&gt;();\r\n        if (search != null) {\r\n            Pattern pattern = Pattern.compile(\"(\\\\w+?)(:|!:|&lt;|&lt;=|&gt;|&gt;=)(\\\\w+?),\");\r\n            Matcher matcher = pattern.matcher(search + \",\");\r\n            while (matcher.find()) {\r\n            \tparams.add(new SearchCriteria(matcher.group(1), \r\n                  matcher.group(2), matcher.group(3)));\r\n            }\r\n        }\r\n        return params;\r\n}<\/pre>\n<h1>The Controller<\/h1>\n<p>The controller which has suffered most of the changes is this one. You will notice that we have added a pagination feature configured by:<\/p>\n<ul>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestParam(value = \"page\", required = <\/code><strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">false<\/code><\/strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">, defaultValue = \"0\") Integer page<\/code>: Zero-based page index. Retrieves all rows from a certain offset up.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestParam(value = \"size\", required = <\/code><strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">false<\/code><\/strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">, defaultValue = \"10\") Integer size<\/code>: The size of the page to be returned. Limits the number of results returned.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestParam(value = \"direction\", required = <\/code><strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">false<\/code><\/strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">, defaultValue = \"asc\") String direction<\/code>: Used to sort the result-set in ascending or descending direction. Direction must not be <code>null<\/code>.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestParam(value = \"orderBy\", required = <\/code><strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">false<\/code><\/strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">, defaultValue = \"authorId\") String orderBy<\/code>: The field name which is used to order the result-set. Properties must not be <code>null<\/code>.<\/li>\n<li>You may have also noticed, that there are two types of searches:<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestParam(value = \"searchAuthor\", required = <\/code><strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">false<\/code><\/strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">) String searchAuthor<\/code>: Use for filtering authors based on the author\u2019s properties.<\/li>\n<li><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestParam(value = \"searchBooks\", required = <\/code><strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">false<\/code><\/strong><code class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">) String searchBooks<\/code>: Use for filtering authors based on the book\u2019s properties.<\/li>\n<\/ul>\n<p>Using them is very simple. Just assign the different filter conditions to either or both request parameters, separated by comma. For instance:<\/p>\n<p><code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\">http:\/\/localhost:8080\/author?searchAuthor=firstName:Juan&amp;searchBooks=year:1990<\/code><\/p>\n<p>The above example creates two filters. For the author, it only will look for authors which first name iguals <code>\u201cJuan\u201d<\/code>. While for the books, it will only look for books which publishing year equals <code>\u201c1990\u201d<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)\r\npublic ResponseEntity&lt;JsonResponseCreator&lt;AuthorResponse&gt;&gt; search(\r\n  @RequestParam(value = \"searchAuthor\", required = false) String searchAuthor,\r\n  @RequestParam(value = \"searchBooks\", required = false) String searchBooks,\r\n  @RequestParam(value = \"page\", required = false, defaultValue = \"0\") Integer page,\t\t\t\t\/\/ zero-based page index\r\n  @RequestParam(value = \"size\", required = false, defaultValue = \"10\") Integer size,\t\t\t\t\/\/ the size of the page to be returned\r\n  @RequestParam(value = \"direction\", required = false, defaultValue = \"asc\") String direction,\t\t\t\/\/ direction must not be {@literal null}\r\n  @RequestParam(value = \"orderBy\", required = false, defaultValue = \"authorId\") String orderBy\t\t\t\/\/ properties must not be {@literal null}\r\n) {\r\n  List&lt;SearchCriteria&gt; paramsAuthor = this.setSearchCriteria(searchAuthor);\r\n  List&lt;SearchCriteria&gt; paramsBooks = this.setSearchCriteria(searchBooks);\r\n        \r\n  Page&lt;Author&gt; pagedContent = this.authorService.search(paramsAuthor, paramsBooks, PageRequest.of(page, size, Direction.fromString(direction), orderBy));\r\n  \r\n  List&lt;AuthorResponse&gt; response = RestResponseBuilder.createAuthorResponseList(pagedContent.getContent());\r\n  JsonResponseCreator&lt;AuthorResponse&gt; jsonResponseCreator = new JsonResponseCreator&lt;AuthorResponse&gt;(pagedContent.getTotalElements(), page, size, direction, orderBy, response);\r\n\r\n  return new ResponseEntity&lt;JsonResponseCreator&lt;AuthorResponse&gt;&gt;(jsonResponseCreator, HttpStatus.OK);\r\n}\r\n<\/pre>\n<h1>Conclusion<\/h1>\n<p>The presented implementation of REST API is simple, but yet very powerful due to its search feature. Of course, there is still room for improvements (which will be implemented in future articles), but it will give you a solid starting point.<\/p>\n<p>The full implementation of this article can be found in the <a href=\"https:\/\/github.com\/canchito-dev\/rest-api-with-jpa-criteria\">GitHub<\/a> project \u2013 this is a Maven-based project, so it should be easy to import and run as it is.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this guide, you will learn how to set up and build a simple REST API with Spring, that provides CRUD operations for entries that are saved into a database. In addition, you will learn how use JPA&#8217;s criteria API to perform filtered searches for records.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[37,15,3],"tags":[16,13,17,10,11,5],"class_list":["post-237","post","type-post","status-publish","format-standard","hentry","category-jpa","category-rest","category-spring","tag-api","tag-java","tag-jpa","tag-open-source","tag-rest","tag-spring"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p8EwXo-3P","jetpack-related-posts":[{"id":34,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2017\/04\/22\/build-a-rest-api-with-spring\/","url_meta":{"origin":237,"position":0},"title":"Build a REST API with Spring","author":"canchitodev","date":"April 22, 2017","format":false,"excerpt":"In this guide, you will learn how to set up and build a simple REST API with Spring, that provides CRUD operations for entries that are saved into a database. In addition, you will learn how to map HTTP request to specific URL and its response codes, and how to\u2026","rel":"","context":"In &quot;REST&quot;","block_context":{"text":"REST","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/rest\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":477,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2020\/06\/27\/use-flowable-apps-with-a-custom-rest-api\/","url_meta":{"origin":237,"position":1},"title":"Use Flowable Apps with a Custom REST API","author":"canchitodev","date":"June 27, 2020","format":false,"excerpt":"In this post, you will learn how configure Flowable's apps to use your custom Spring Boot REST API as a backend engine. All this, in a dockerized environment.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"CANCHITO-DEV: Process engine deployments in Flowable Admin","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=700%2C400 2x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2020\/05\/process-engine-deployments.png?resize=1050%2C600 3x"},"classes":[]},{"id":263,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2018\/06\/11\/spring-boot-actuator-production-ready-features\/","url_meta":{"origin":237,"position":2},"title":"Spring Boot Actuator &#8211; Production-ready features","author":"canchitodev","date":"June 11, 2018","format":false,"excerpt":"In this post, we\u2019re going to introduce Spring Boot Actuator, by first covering the basics. Afterwards,\u00a0you will create a Spring project and learn how to use, configure and extend this monitoring tool.","rel":"","context":"In &quot;Actuator&quot;","block_context":{"text":"Actuator","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/actuator\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":27,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2017\/04\/30\/integrate-activiti-bpm-with-spring\/","url_meta":{"origin":237,"position":3},"title":"Integrate Activiti BPM with Spring","author":"canchitodev","date":"April 30, 2017","format":false,"excerpt":"In this post, you will learn how to integrate Activiti's engine and REST API into your Spring application. At the same time, you will be able to adapt the Process Engine to your needs by modifying the database connection and the Async Job Executor.","rel":"","context":"In &quot;Activiti BPM&quot;","block_context":{"text":"Activiti BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/activiti-bpm\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":356,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2019\/07\/05\/run-flowable-bpm-using-docker-and-mysql\/","url_meta":{"origin":237,"position":4},"title":"Run Flowable BPM using Docker and MySQL","author":"canchitodev","date":"July 5, 2019","format":false,"excerpt":"In this article, you will learn how to compile Flowable source code using MySQL as database source, and generate valid Docker images. Once you have the images, we will use Docker Compose for defining and running a multi-container Docker applications.","rel":"","context":"In &quot;BPM&quot;","block_context":{"text":"BPM","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/bpm\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":361,"url":"http:\/\/www.canchito-dev.com\/public\/blog\/2019\/07\/22\/spring-cloud-config-server-and-client-side-support-for-externalized-configuration\/","url_meta":{"origin":237,"position":5},"title":"Spring Cloud Config &#8211; Server and client-side support for externalized configuration","author":"canchitodev","date":"July 22, 2019","format":false,"excerpt":"Want to learn how to manage your application configuration in a distributed environment? Learn how to do it with Spring Cloud Config.","rel":"","context":"In &quot;Spring&quot;","block_context":{"text":"Spring","link":"http:\/\/www.canchito-dev.com\/public\/blog\/category\/spring\/"},"img":{"alt_text":"CANCHITO-DEV: Spring Boot Config - Server and client-side support for externalized configuration","src":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2019\/07\/Spring-Boot-Config-Server-and-client-side-support-for-externalized-configuration.png?resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2019\/07\/Spring-Boot-Config-Server-and-client-side-support-for-externalized-configuration.png?resize=350%2C200 1x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2019\/07\/Spring-Boot-Config-Server-and-client-side-support-for-externalized-configuration.png?resize=525%2C300 1.5x, https:\/\/i0.wp.com\/www.canchito-dev.com\/public\/blog\/wp-content\/uploads\/2019\/07\/Spring-Boot-Config-Server-and-client-side-support-for-externalized-configuration.png?resize=700%2C400 2x"},"classes":[]}],"jetpack_likes_enabled":true,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/237","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/comments?post=237"}],"version-history":[{"count":9,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/237\/revisions"}],"predecessor-version":[{"id":549,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/posts\/237\/revisions\/549"}],"wp:attachment":[{"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/media?parent=237"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/categories?post=237"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.canchito-dev.com\/public\/blog\/wp-json\/wp\/v2\/tags?post=237"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}