<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: MaxiCB</title>
    <description>The latest articles on DEV Community by MaxiCB (@maxicb).</description>
    <link>https://dev.to/maxicb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F421791%2Fdcdc561a-f447-4393-ae55-32c61dd35575.jpeg</url>
      <title>DEV Community: MaxiCB</title>
      <link>https://dev.to/maxicb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/maxicb"/>
    <language>en</language>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 9</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Sat, 19 Jun 2021 03:33:11 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-9-3pj5</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-9-3pj5</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 9
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 9 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pagination Support

&lt;ul&gt;
&lt;li&gt;We will update our backend to support pagination, this will reduce the amount of loading times for the client as the database begins to scale&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;JWT Invalidation&lt;/li&gt;

&lt;li&gt;JWT Refreshing&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n"&gt;Part 8&lt;/a&gt; we added the CREATE &amp;amp;&amp;amp; READ endpoints for creating and reading comments!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Updating Repositories 🗄
&lt;/h2&gt;

&lt;p&gt;Let's cover the updating of all of our repositories to implement pagination and sorting support. Inside &lt;strong&gt;com.your-name.backend.repository&lt;/strong&gt; we will update the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentRespository: We will convert our existing logic, as well as add a findAllByPost method that still returns a list, as we rely on that for sending back the total amount of comments in our PostService
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.repository;

import com.maxicb.backend.model.Comment;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.util.List;

public interface CommentRepository extends PagingAndSortingRepository&amp;lt;Comment, Long&amp;gt; {
    Page&amp;lt;Comment&amp;gt; findByPost(Post post, Pageable pageable);
    List&amp;lt;Comment&amp;gt; findAllByPost(Post post);
    Page&amp;lt;Comment&amp;gt; findAllByUser(User user, Pageable pageable);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;PostRepository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.repository;

import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.Subreddit;
import com.maxicb.backend.model.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.util.List;

public interface PostRepository extends PagingAndSortingRepository&amp;lt;Post, Long&amp;gt; {
    Page&amp;lt;Post&amp;gt; findAllBySubreddit(Subreddit subreddit, Pageable pageable);
    Page&amp;lt;Post&amp;gt; findByUser(User user, Pageable pageable);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;SubredditRepository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.repository;

import com.maxicb.backend.model.Subreddit;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.util.Optional;

public interface SubredditRepository extends PagingAndSortingRepository&amp;lt;Subreddit, Long&amp;gt; {
    Optional&amp;lt;Subreddit&amp;gt; findByName(String subredditName);
    Optional&amp;lt;Page&amp;lt;Subreddit&amp;gt;&amp;gt; findByNameLike(String subredditName, Pageable pageable);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Updating Services 🌎
&lt;/h2&gt;

&lt;p&gt;Now that we have updated our repositories we will need to update our servcies to refelct these changes. Inside &lt;strong&gt;com.your-name.backend.service&lt;/strong&gt; we will update the following classes. Keep in mind I will not be displaying the whole class in the section, but only the specific methods we will be updating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentService: We will update the getCommentsForPost &amp;amp;&amp;amp; getCommentsForUser methods to handle pagination properly
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public Page&amp;lt;CommentResponse&amp;gt; getCommentsForPost(Long id, Integer page) {
        Post post = postRepository.findById(id)
                .orElseThrow(() -&amp;gt; new PostNotFoundException("Post not found with id: " + id));
        return commentRepository.findByPost(post, PageRequest.of(page, 100)).map(this::mapToResponse);
    }

    public Page&amp;lt;CommentResponse&amp;gt; getCommentsForUser(Long id, Integer page) {
        User user = userRepository.findById(id)
                .orElseThrow(() -&amp;gt; new UserNotFoundException("User not found with id: " + id));
        return commentRepository.findAllByUser(user, PageRequest.of(page, 100)).map(this::mapToResponse);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;PostService: We will update the mapToResponse &amp;amp;&amp;amp; getAllPosts &amp;amp;&amp;amp; getPostsBySubreddit &amp;amp;&amp;amp; getPostsByUsername methods to implement pagination, and also retain the existing logic of mapping to DTO's
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    private PostResponse mapToResponse(Post post) {
        return PostResponse.builder()
                .postId(post.getPostId())
                .postTitle(post.getPostTitle())
                .url(post.getUrl())
                .description(post.getDescription())
                .userName(post.getUser().getUsername())
                .subredditName(post.getSubreddit().getName())
                .voteCount(post.getVoteCount())
                .commentCount(commentRepository.findAllByPost(post).size())
                .duration(TimeAgo.using(post.getCreationDate().toEpochMilli()))
                .upVote(checkVoteType(post, VoteType.UPVOTE))
                .downVote(checkVoteType(post, VoteType.DOWNVOTE))
                .build();
    }

    public Page&amp;lt;PostResponse&amp;gt; getAllPost(Integer page) {
        return postRepository.findAll(PageRequest.of(page, 100)).map(this::mapToResponse);
    }

    public Page&amp;lt;PostResponse&amp;gt; getPostsBySubreddit(Integer page, Long id) {
        Subreddit subreddit = subredditRepository.findById(id)
                .orElseThrow(() -&amp;gt; new SubredditNotFoundException("Subreddit not found with id: " + id));
        return postRepository
                .findAllBySubreddit(subreddit, PageRequest.of(page, 100))
                .map(this::mapToResponse);
    }

    public Page&amp;lt;PostResponse&amp;gt; getPostsByUsername(String username, Integer page) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -&amp;gt; new UserNotFoundException("User not found with username: " + username));
        return postRepository
                .findByUser(user, PageRequest.of(page, 100))
                .map(this::mapToResponse);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;SubredditService: We will update the getAll method
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @Transactional(readOnly = true)
    public Page&amp;lt;SubredditDTO&amp;gt; getAll(Integer page) {
        return subredditRepository.findAll(PageRequest.of(page, 100))
                .map(this::mapToDTO);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Updating Controllers
&lt;/h2&gt;

&lt;p&gt;Now that we have updated our services &amp;amp;&amp;amp; repositories we will need to update our controllers to allow client to use pagination. Inside &lt;strong&gt;com.your-name.backend.controller&lt;/strong&gt; we will update the following classes. Keep in mind I will not be displaying the whole class in the section, but only the specific methods we will be updating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentController: We will update the getCommentsByPost &amp;amp;&amp;amp; getCommentsByUser methods to handle pagination properly
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @GetMapping("/post/{id}")
    public ResponseEntity&amp;lt;Page&amp;lt;CommentResponse&amp;gt;&amp;gt; getCommentsByPost(@PathVariable("id") Long id, @RequestParam Optional&amp;lt;Integer&amp;gt; page) {
        return new ResponseEntity&amp;lt;&amp;gt;(commentService.getCommentsForPost(id, page.orElse(0)), HttpStatus.OK);
    }

    @GetMapping("/user/{id}")
    public ResponseEntity&amp;lt;Page&amp;lt;CommentResponse&amp;gt;&amp;gt; getCommentsByUser(@PathVariable("id") Long id,@RequestParam Optional&amp;lt;Integer&amp;gt; page) {
        return new ResponseEntity&amp;lt;&amp;gt;(commentService.getCommentsForUser(id, page.orElse(0)), HttpStatus.OK);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;PostController: We will update the addPost method firstly to send the created post back to the client on successful creation, getAllPost &amp;amp;&amp;amp; getPostsBySubreddit &amp;amp;&amp;amp; getPostsByUsername methods to implement pagination
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @PostMapping
    public ResponseEntity&amp;lt;PostResponse&amp;gt; addPost(@RequestBody PostRequest postRequest) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.save(postRequest), HttpStatus.CREATED);
    }

    @GetMapping
    public ResponseEntity&amp;lt;Page&amp;lt;PostResponse&amp;gt;&amp;gt; getAllPost(@RequestParam Optional&amp;lt;Integer&amp;gt; page) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.getAllPost(page.orElse(0)), HttpStatus.OK);
    }

    @GetMapping("/sub/{id}")
    public ResponseEntity&amp;lt;Page&amp;lt;PostResponse&amp;gt;&amp;gt; getPostsBySubreddit(@PathVariable Long id, @RequestParam Optional&amp;lt;Integer&amp;gt; page) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.getPostsBySubreddit(page.orElse(0), id), HttpStatus.OK);
    }

    @GetMapping("/user/{name}")
    public ResponseEntity&amp;lt;Page&amp;lt;PostResponse&amp;gt;&amp;gt; getPostsByUsername(@PathVariable("name") String username, @RequestParam Optional&amp;lt;Integer&amp;gt; page) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.getPostsByUsername(username, page.orElse(0)), HttpStatus.OK);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;SubredditController: We will update all of the methods to implement sending ResponseEntity as well as support pagination
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    @GetMapping("/{page}")
    public ResponseEntity&amp;lt;Page&amp;lt;SubredditDTO&amp;gt;&amp;gt; getAllSubreddits (@PathVariable("page") Integer page) {
        return new ResponseEntity&amp;lt;&amp;gt;(subredditService.getAll(page), HttpStatus.OK);
    }

    @GetMapping("/sub/{id}")
    public ResponseEntity&amp;lt;SubredditDTO&amp;gt; getSubreddit(@PathVariable("id") Long id) {
        return new ResponseEntity&amp;lt;&amp;gt;(subredditService.getSubreddit(id), HttpStatus.OK);
    }

    @PostMapping
    public ResponseEntity&amp;lt;SubredditDTO&amp;gt; addSubreddit(@RequestBody @Valid SubredditDTO subredditDTO) throws Exception{
        try {
            return new ResponseEntity&amp;lt;&amp;gt;(subredditService.save(subredditDTO), HttpStatus.OK);
        } catch (Exception e) {
            throw new Exception("Error Creating Subreddit");
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Now our appliction fully supports pagination for all resources that could grow and cause slow load time for our front end application!
&lt;/h3&gt;

&lt;h2&gt;
  
  
  Part 5: Refresh Token Class ⏳
&lt;/h2&gt;

&lt;p&gt;Now we need to create our RefreshToken class, this class will have a ID, token, and the creationDate associated with it to allow for invalidating tokens after a set amount of time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RefreshToken:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.Instant;

@Data
@Entity
@AllArgsConstructor
@NoArgsConstructor
public class RefreshToken {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String token;
    private Instant creationDate;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Refresh Token Service and DTO🌎
&lt;/h2&gt;

&lt;p&gt;Now that we have our RefreshToken, we will get everything in place to begin updating our Authentication system. Inside the project we will add, and update the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RefreshTokenRepository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.repository;

import com.maxicb.backend.model.RefreshToken;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.util.Optional;

public interface RefreshTokenRepository extends PagingAndSortingRepository&amp;lt;RefreshToken, Long&amp;gt; {
    Optional&amp;lt;RefreshToken&amp;gt; findByToken(String token);

    void deleteByToken(String token);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;RefreshTokenService: This service will allow us to generate tokens, validate tokens, and delete tokens.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.exception.VoxNobisException;
import com.maxicb.backend.model.RefreshToken;
import com.maxicb.backend.repository.RefreshTokenRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.UUID;

@Service
@AllArgsConstructor
@Transactional
public class RefreshTokenService {
    private RefreshTokenRepository refreshTokenRepository;

    RefreshToken generateRefreshToken () {
        RefreshToken refreshToken = new RefreshToken();
        refreshToken.setToken(UUID.randomUUID().toString());
        refreshToken.setCreationDate(Instant.now());
        return refreshTokenRepository.save(refreshToken);
    }

    void validateToken(String token) {
        refreshTokenRepository.findByToken(token)
                .orElseThrow(() -&amp;gt; new VoxNobisException("Invalid Refresh Token"));
    }

    public void deleteRefreshToken(String token) {
        refreshTokenRepository.deleteByToken(token);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Updated AuthResponse: We will update the AuthResponse to include our newly generated token.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import lombok.AllArgsConstructor;
import lombok.Data;

import java.time.Instant;

@Data
@AllArgsConstructor
public class AuthResponse {
        private String authenticationToken;
        private String refreshToken;
        private Instant expiresAt;
        private String username;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;RefreshTokenRequest: This DTO will handle requests from the client to refresh their token, before it expires in the system
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.validation.constraints.NotBlank;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RefreshTokenRequest {
    @NotBlank
    private String refreshToken;
    private String username;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 6: JWTProvider Update 🔏
&lt;/h2&gt;

&lt;p&gt;Now that we have everything in place, we will begin updating our JWT system. Inside &lt;strong&gt;com.your-name.backend.service&lt;/strong&gt; we will update the following classes. Keep in mind I will not be displaying the whole class in the section, but only the specific methods we will be updating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWTProvider: We will update our JWT implementation to include a issuedAt date, and also set a expiration date when we create a new token.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Service
public class JWTProvider {
    private KeyStore keystore;
    @Value("${jwt.expiration.time}")
    private Long jwtExpirationMillis;

    ...
    ....
    public String generateToken(Authentication authentication) {
        org.springframework.security.core.userdetails.User princ = (User) authentication.getPrincipal();
        return Jwts.builder()
                .setSubject(princ.getUsername())
                .setIssuedAt(from(Instant.now()))
                .signWith(getPrivKey())
                .setExpiration(from(Instant.now().plusMillis(jwtExpirationMillis)))
                .compact();
    }

    public String generateTokenWithUsername(String username) {
        return Jwts.builder()
                .setSubject(username)
                .setIssuedAt(from(Instant.now()))
                .signWith(getPrivKey())
                .setExpiration(from(Instant.now().plusMillis(jwtExpirationMillis)))
                .compact();
    }
    ....
    ...
    public Long getJwtExpirationMillis() {
        return jwtExpirationMillis;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 7: Updated Authentication 💂‍♀️
&lt;/h2&gt;

&lt;p&gt;Now that we implemented pagination, we will begin updating our Authentication system. Inside our project we will update the following classes. Keep in mind I will not be displaying the whole class in the section, but only the specific methods we will be updating.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthService: We will update our AuthService to handle sending refreshTokens, and add the logic for refreshing existing tokens.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;public AuthResponse refreshToken(RefreshTokenRequest refreshTokenRequest) {
        refreshTokenService.validateToken(refreshTokenRequest.getRefreshToken());
        String token = jwtProvider.generateTokenWithUsername(refreshTokenRequest.getUsername());
        return new AuthResponse(token, refreshTokenService.generateRefreshToken().getToken(), Instant.now().plusMillis(jwtProvider.getJwtExpirationMillis()), refreshTokenRequest.getUsername());
    }

public AuthResponse login (LoginRequest loginRequest) {
        Authentication authenticate = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(), loginRequest.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        String authToken = jwtProvider.generateToken(authenticate);
        String refreshToken = refreshTokenService.generateRefreshToken().getToken();
        return new AuthResponse(authToken, refreshToken, Instant.now().plusMillis(jwtProvider.getJwtExpirationMillis()), loginRequest.getUsername());
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;AuthController: We will now implement the new endpoints to allow the client to use the newly added logic.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@PostMapping("/refresh/token")
    public AuthResponse refreshToken(@Valid @RequestBody RefreshTokenRequest refreshTokenRequest) {
        return authService.refreshToken(refreshTokenRequest);
    }

    @PostMapping("/logout")
    public ResponseEntity&amp;lt;String&amp;gt; logout(@Valid @RequestBody RefreshTokenRequest refreshTokenRequest) {
        refreshTokenService.deleteRefreshToken(refreshTokenRequest.getRefreshToken());
        return ResponseEntity.status(HttpStatus.OK).body("Refresh Token Deleted");
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 8: Custom Exception 🚫
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;VoxNobisException: We will create a general purpose custom exception that can be used repeatedly throughout our application as we extend it.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.exception;

public class VoxNobisException extends RuntimeException {
    public VoxNobisException(String message) {super(message);}
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 9: Updated application.properties
&lt;/h2&gt;

&lt;p&gt;We will need to add the expiration time that we would like our application to use when it comes to generating tokens, and setting their expiration dates accordingly. I have chose to set it to 15 minutes, but in the future will increase the duration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# JWT Properties
jwt.expiration.time=900000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 10: Implementing Swagger UI 📃
&lt;/h2&gt;

&lt;p&gt;Now that we are at the end of our MVP backend, we will add Swagger UI. If you have never used Swagger before, it is a great way to automatically generate documentation for your API. You can learn more &lt;a href="https://swagger.io/tools/swagger-ui/" rel="noopener noreferrer"&gt;here!&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;pom.xml: We will need to include the swagger dependencies inside our project's pom.xml file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.springfox&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;springfox-swagger2&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.9.2&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
        &amp;lt;dependency&amp;gt;
            &amp;lt;groupId&amp;gt;io.springfox&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;springfox-swagger-ui&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.9.2&amp;lt;/version&amp;gt;
        &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;SwaggerConfig: Inside &lt;strong&gt;com.your-name.backend.config&lt;/strong&gt; we will create the following class.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket voxNobisAPI() {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any())
                .build()
                .apiInfo(getAPIInfo());
    }

    private ApiInfo getAPIInfo(){
        return new ApiInfoBuilder()
                .title("Vox-Nobis API")
                .version("1.0")
                .description("API for Vox-Nobis reddit clone")
                .build();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;BackendApplication: Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; we will inject our Swagger configuration.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootApplication
@EnableAsync
@Import(SwaggerConfig.class)
public class BackendApplication {
    ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Security: If you run the application now, and try to navigate to &lt;strong&gt;&lt;a href="http://localhost:8080/swagger-ui.html#/" rel="noopener noreferrer"&gt;http://localhost:8080/swagger-ui.html#/&lt;/a&gt;&lt;/strong&gt;, you will likely get a 403 forbidden error. Inside &lt;strong&gt;com.your-name.backend.config&lt;/strong&gt; we will need to update our security configuration to allow access without authorization by adding the following matchers underneath our existing one.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.antMatchers(HttpMethod.GET, "/api/subreddit")
.permitAll()
.antMatchers("/v2/api-docs",
            "/configuration/ui",
            "/swagger-resources/**",
            "/configuration/security",
            "/swagger-ui.html",
            "/webjars/**")
.permitAll()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" title="Successful Run" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If there are no error's in the console you can test the new logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/auth/login" rel="noopener noreferrer"&gt;http://localhost:8080/api/auth/login&lt;/a&gt;&lt;/strong&gt; with the correct data, upon successful login you should receive the refreshToken, and username back now!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also navigate to &lt;strong&gt;&lt;a href="http://localhost:8080/swagger-ui.html#/" rel="noopener noreferrer"&gt;http://localhost:8080/swagger-ui.html#/&lt;/a&gt;&lt;/strong&gt;, and view the documentation for all of the endpoints we have created, as well as the information they need, and return.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In this article we added pagination, and token expiration times.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Follow to get informed when part ten is released, where we will begin working on the Front End of the application!
&lt;/h3&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 8</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Wed, 10 Mar 2021 04:38:38 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-8-oa7</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-8-oa7</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 8
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 8 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vote DTO&lt;/li&gt;
&lt;li&gt;Vote Exception&lt;/li&gt;
&lt;li&gt;Vote Service&lt;/li&gt;
&lt;li&gt;Vote Controller&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n"&gt;Part 7&lt;/a&gt; we added the CREATE &amp;amp;&amp;amp; READ endpoints for creating and reading comments!!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Vote DTO 📨
&lt;/h2&gt;

&lt;p&gt;Let's cover our the DTO's we will need for receiving and sending Vote information. Inside &lt;strong&gt;com.your-name.backend.dto&lt;/strong&gt; we will create the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VoteDTO: Handles creation of the data that will be sent from the client to the API.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import com.maxicb.backend.model.VoteType;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class VoteDTO {
    private VoteType voteType;
    private Long id;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Vote Exception 🚫
&lt;/h2&gt;

&lt;p&gt;Let's cover our custom exceptions we will need. Inside &lt;strong&gt;com.your-name.backend.exception&lt;/strong&gt; we will create the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VoteException: Handles exceptions related to looking for a invalid user.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.exception;

public class VoteException extends RuntimeException {
        public VoteException(String message) {
            super(message);
        }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Vote Service 🌎
&lt;/h2&gt;

&lt;p&gt;Let's cover the vote service our application will have. Inside &lt;strong&gt;com.your-name.backend.services&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VoteService: Hold the logic for mapping data to and from DTO's, and adding votes to a post.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.dto.VoteDTO;
import com.maxicb.backend.exception.PostNotFoundException;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.Vote;
import com.maxicb.backend.repository.PostRepository;
import com.maxicb.backend.repository.VoteRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

import static com.maxicb.backend.model.VoteType.UPVOTE;

@Service
@AllArgsConstructor
public class VoteService {
    private final VoteRepository voteRepository;
    private final PostRepository postRepository;
    private final AuthService authService;

    private Vote maptoVote(VoteDTO voteDTO, Post post) {
        return Vote.builder()
                .voteType(voteDTO.getVoteType())
                .post(post)
                .user(authService.getCurrentUser())
                .build();
    }

    @Transactional
    public void vote(VoteDTO voteDTO) {
        Post post = postRepository.findById(voteDTO.getId())
                .orElseThrow(() -&amp;gt; new PostNotFoundException("Post not found with id:" + voteDTO.getId()));
        Optional&amp;lt;Vote&amp;gt; votePostAndUser = voteRepository.findTopByPostAndUserOrderByVoteIdDesc(post, authService.getCurrentUser());
        if(votePostAndUser.isPresent() &amp;amp;&amp;amp; votePostAndUser.get().getVoteType().equals(voteDTO.getVoteType())) {
            throw new PostNotFoundException("You've already " + voteDTO.getVoteType() + "'d this post");
        }
        if(UPVOTE.equals(voteDTO.getVoteType())) {
            post.setVoteCount(post.getVoteCount() + 1);
        } else {
            post.setVoteCount(post.getVoteCount() - 1);
        }
        voteRepository.save(maptoVote(voteDTO, post));
        postRepository.save(post);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: Vote Controller 🌐
&lt;/h2&gt;

&lt;p&gt;Let's cover the vote controller our application will have. Inside &lt;strong&gt;com.your-name.backend.controller&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;VoteController: Hold the endpoints adding votes to a specific post.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.controller;

import com.maxicb.backend.dto.VoteDTO;
import com.maxicb.backend.service.VoteService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/vote")
@AllArgsConstructor
public class VoteController {

    private final VoteService voteService;

    @PostMapping
    public ResponseEntity&amp;lt;Void&amp;gt; vote(@RequestBody VoteDTO voteDTO) {
        voteService.vote(voteDTO);
        return new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.OK);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" title="Successful Run" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no error's in the console you can test the voting logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/vote" rel="noopener noreferrer"&gt;http://localhost:8080/api/vote&lt;/a&gt;&lt;/strong&gt; with the following data. You will still have to follow the same steps covered in the previous parts to login to an account to make post's, as well as create a subreddit, and valid post to add a comment to.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "voteType": "UPVOTE",
    "id": &amp;lt;post-id&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You can now make a GET reguest to &lt;strong&gt;&lt;a href="http://localhost:8080/api/posts/" rel="noopener noreferrer"&gt;http://localhost:8080/api/posts/&lt;/a&gt;&lt;/strong&gt; to see the voteCount change on the post you just upvoted.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "postId": 9,
    "postTitle": "Testing Post",
    "url": "URL",
    "description": "DESCRIPTION",
    "userName": "USERNAME",
    "subredditName": "/r/NAME",
    "voteCount": 1,
    "commentCount": 1,
    "duration": "4 hours ago",
    "upVote": true,
    "downVote": false
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this article we implemented the logic for voting on post's!.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Follow to get informed when part nine is released, where we will cover the post voting functionality! If you have any questions be sure to leave a comment!
&lt;/h3&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>typescript</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 7</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Mon, 18 Jan 2021 13:04:07 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-7-17mg</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-7-17mg</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 7
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 7 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Comment Request DTO&lt;/li&gt;
&lt;li&gt;Comment Response DTO&lt;/li&gt;
&lt;li&gt;Update Comment Repository&lt;/li&gt;
&lt;li&gt;Comment Service&lt;/li&gt;
&lt;li&gt;READ Comment Endpoint's&lt;/li&gt;
&lt;li&gt;CREATE Comment Endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n"&gt;Part 6&lt;/a&gt; we added some custom exceptions, and made our post endpoint's!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Comment DTO's 📨
&lt;/h2&gt;

&lt;p&gt;Let's cover our the various DTO's we will need for comments. Inside &lt;strong&gt;com.your-name.backend.dto&lt;/strong&gt; we will create the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentRequest: Handles creation of the data that will be sent from the client to the API.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import com.maxicb.backend.model.Post;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CommentRequest {
    private Long id;
    private String text;
    private Post post;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;CommentResponse: Handles creation of the data that will be sent to the client from the API.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import com.maxicb.backend.model.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.Instant;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class CommentResponse {
    private Long id;
    private String text;
    private Long postId;
    private Instant creationDate;
    private User user;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Update Comment Repository 📨
&lt;/h2&gt;

&lt;p&gt;Let's cover updating our comment repository to support pagination, and sorting. Inside &lt;strong&gt;com.your-name.backend.repository&lt;/strong&gt; we will Update the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentRepository
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.repository;

import com.maxicb.backend.model.Comment;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.User;
import org.springframework.data.repository.PagingAndSortingRepository;

import java.util.List;

public interface CommentRepository extends PagingAndSortingRepository&amp;lt;Comment, Long&amp;gt; {
    List&amp;lt;Comment&amp;gt; findByPost(Post post);

    List&amp;lt;Comment&amp;gt; findAllByUser(User user);
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Comment Service 🌎
&lt;/h2&gt;

&lt;p&gt;Let's cover the comment service our application will have. Inside &lt;strong&gt;com.your-name.backend.services&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentService: Hold the logic for mapping data to and from DTO's, getting all comments's by postId, getting user specific comments's, and adding comments's to post's.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.github.marlonlom.utilities.timeago.TimeAgo;
import com.maxicb.backend.dto.CommentRequest;
import com.maxicb.backend.dto.CommentResponse;
import com.maxicb.backend.exception.PostNotFoundException;
import com.maxicb.backend.exception.UserNotFoundException;
import com.maxicb.backend.model.Comment;
import com.maxicb.backend.model.Post;
import com.maxicb.backend.model.User;
import com.maxicb.backend.repository.CommentRepository;
import com.maxicb.backend.repository.PostRepository;
import com.maxicb.backend.repository.UserRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
@Transactional
public class CommentService {
    private final UserRepository userRepository;
    private final PostRepository postRepository;
    private final CommentRepository commentRepository;
    private final AuthService authService;

    private CommentResponse mapToResponse(Comment comment) {
        return CommentResponse.builder()
                .id(comment.getId())
                .text(comment.getText())
                .postId(comment.getPost().getPostId())
                .creationDate(TimeAgo.using(comment.getCreationDate().toEpochMilli()))
                .userName(comment.getUser().getUsername())
                .build();
    }

    private Comment mapToComment(CommentRequest commentRequest) {
        User user = authService.getCurrentUser();
        Post post = postRepository.findById(commentRequest.getPostId())
                .orElseThrow(() -&amp;gt; new PostNotFoundException("Post not found with id: " + commentRequest.getPostId()));
        return Comment.builder()
                .text(commentRequest.getText())
                .post(post)
                .creationDate(Instant.now())
                .user(user)
                .build();
    }

    public CommentResponse save(CommentRequest commentRequest) {
        return mapToResponse(commentRepository.save(mapToComment(commentRequest)));
    }

    public List&amp;lt;CommentResponse&amp;gt; getCommentsForPost(Long id) {
        Post post = postRepository.findById(id)
                .orElseThrow(() -&amp;gt; new PostNotFoundException("Post not found with id: " + id));
        return commentRepository.findByPost(post)
                .stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    public List&amp;lt;CommentResponse&amp;gt; getCommentsForUser(Long id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -&amp;gt; new UserNotFoundException("User not found with id: " + id));
        return commentRepository.findAllByUser(user)
                .stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: Comment Controller 🌐
&lt;/h2&gt;

&lt;p&gt;Let's cover the comment controller our application will have. Inside &lt;strong&gt;com.your-name.backend.controller&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CommentController: Hold the endpoints for fetching creating comments, fetching comments on a post, and specific user comments.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.controller;

import com.maxicb.backend.dto.CommentRequest;
import com.maxicb.backend.dto.CommentResponse;
import com.maxicb.backend.service.CommentService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/comments")
@AllArgsConstructor
public class CommentController {
    private final CommentService commentService;

    @PostMapping
    public ResponseEntity&amp;lt;CommentResponse&amp;gt; addComment(@RequestBody CommentRequest commentRequest) {
        return new ResponseEntity&amp;lt;&amp;gt;(commentService.save(commentRequest), HttpStatus.CREATED);
    }

    @GetMapping("/post/{id}")
    public ResponseEntity&amp;lt;List&amp;lt;CommentResponse&amp;gt;&amp;gt; getCommentsByPost(@PathVariable Long id) {
        return new ResponseEntity&amp;lt;&amp;gt;(commentService.getCommentsForPost(id), HttpStatus.OK);
    }

    @GetMapping("/user/{id}")
    public ResponseEntity&amp;lt;List&amp;lt;CommentResponse&amp;gt;&amp;gt; getCommentsByUser(@PathVariable Long id) {
        return new ResponseEntity&amp;lt;&amp;gt;(commentService.getCommentsForUser(id), HttpStatus.OK);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" title="Successful Run" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no error's in the console you can test the comment creation logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/comments" rel="noopener noreferrer"&gt;http://localhost:8080/api/comments&lt;/a&gt;&lt;/strong&gt; with the following data. You will still have to follow the same steps covered in the previous parts to login to an account to make post's, as well as create a subreddit, and valid post to add a comment to.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "postId": &amp;lt;post-id&amp;gt;,
    "text": "My First Comment!!"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this article we added the CREATE &amp;amp;&amp;amp; READ endpoints for creating and reading comments!.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Voting System! &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-8-oa7"&gt;Part 8&lt;/a&gt;
&lt;/h3&gt;

</description>
      <category>react</category>
      <category>typescript</category>
      <category>java</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 6</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Thu, 20 Aug 2020 19:44:37 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-6-5e33</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-6-5e33</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 6
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 6 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post Request DTO&lt;/li&gt;
&lt;li&gt;Post Response DTO&lt;/li&gt;
&lt;li&gt;Custom Exceptions&lt;/li&gt;
&lt;li&gt;Updated Auth Service&lt;/li&gt;
&lt;li&gt;Post Service&lt;/li&gt;
&lt;li&gt;READ Post Endpoint's&lt;/li&gt;
&lt;li&gt;Create Post Endpoint&lt;/li&gt;
&lt;li&gt;Updated application.properties&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-5-2h8j"&gt;Part 5&lt;/a&gt; we created the logic needed for JWT filtering, updated our authentication service, and made our subreddit endpoint's!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Post DTO's 📨
&lt;/h2&gt;

&lt;p&gt;Let's cover our the various DTO's we will need. Inside &lt;strong&gt;com.your-name.backend.dto&lt;/strong&gt; we will create the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostRequest: Handles creation of the data that will be sent from the client to the API.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PostRequest {
    private Long postId;
    private String postTitle;
    private String url;
    private String description;
    private String subredditName;

}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;PostResponse: Handles creation of the data that will be sent to the client from the API.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PostResponse {
    private Long postId;
    private String postTitle;
    private String url;
    private String description;
    private String userName;
    private String subredditName;
    private Integer voteCount;
    private Integer commentCount;
    private String duration;
    private boolean upVote;
    private boolean downVote;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Custom Exceptions 🚫
&lt;/h2&gt;

&lt;p&gt;Let's cover our custom exceptions we will need. Inside &lt;strong&gt;com.your-name.backend.exception&lt;/strong&gt; we will create the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserNotFoundException: Handles exceptions related to looking for a invalid user.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.exception;

public class UserNotFoundException extends RuntimeException {
    public UserNotFoundException(String message) {
        super(message);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;PostNotFoundException: Handles exceptions related to looking for a invalid posting.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.exception;

public class PostNotFoundException extends RuntimeException {
    public PostNotFoundException(String message) {
        super(message);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Updated Auth Service 💂‍♀️
&lt;/h2&gt;

&lt;p&gt;Let's cover our JWT validation logic we will need. Inside &lt;strong&gt;com.your-name.backend.service&lt;/strong&gt; we will update the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthService: We need to implement logic to check if the user is currently logged in.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.dto.AuthResponse;
import com.maxicb.backend.dto.LoginRequest;
import com.maxicb.backend.dto.RegisterRequest;
import com.maxicb.backend.exception.ActivationException;
import com.maxicb.backend.model.AccountVerificationToken;
import com.maxicb.backend.model.NotificationEmail;
import com.maxicb.backend.model.User;
import com.maxicb.backend.repository.TokenRepository;
import com.maxicb.backend.repository.UserRepository;
import com.maxicb.backend.security.JWTProvider;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Optional;
import java.util.UUID;

import static com.maxicb.backend.config.Constants.EMAIL_ACTIVATION;

@Service
@AllArgsConstructor

public class AuthService {

    UserRepository userRepository;
    PasswordEncoder passwordEncoder;
    TokenRepository tokenRepository;
    MailService mailService;
    MailBuilder mailBuilder;
    AuthenticationManager authenticationManager;
    JWTProvider jwtProvider;

    @Transactional
    public void register(RegisterRequest registerRequest) {
        User user = new User();
        user.setUsername(registerRequest.getUsername());
        user.setEmail(registerRequest.getEmail());
        user.setPassword(encodePassword(registerRequest.getPassword()));
        user.setCreationDate(Instant.now());
        user.setAccountStatus(false);

        userRepository.save(user);

        String token = generateToken(user);
        String message = mailBuilder.build("Welcome to React-Spring-Reddit Clone. " +
                "Please visit the link below to activate you account : " + EMAIL_ACTIVATION + "/" + token);
        mailService.sendEmail(new NotificationEmail("Please Activate Your Account", user.getEmail(), message));
    }

    @Transactional(readOnly = true)
    public User getCurrentUser() {
        org.springframework.security.core.userdetails.User principal = (org.springframework.security.core.userdetails.User) SecurityContextHolder.
                getContext().getAuthentication().getPrincipal();
        return userRepository.findByUsername(principal.getUsername())
                .orElseThrow(() -&amp;gt; new UsernameNotFoundException("User not found with username: " + principal.getUsername()));
    }

    public AuthResponse login (LoginRequest loginRequest) {
        Authentication authenticate = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(), loginRequest.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        String authToken = jwtProvider.generateToken(authenticate);
        return new AuthResponse(authToken, loginRequest.getUsername());
    }

    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    private String generateToken(User user) {
        String token = UUID.randomUUID().toString();
        AccountVerificationToken verificationToken = new AccountVerificationToken();
        verificationToken.setToken(token);
        verificationToken.setUser(user);
        tokenRepository.save(verificationToken);
        return token;
    }

    public void verifyToken(String token) {
        Optional&amp;lt;AccountVerificationToken&amp;gt; verificationToken = tokenRepository.findByToken(token);
        verificationToken.orElseThrow(() -&amp;gt; new ActivationException("Invalid Activation Token"));
        enableAccount(verificationToken.get());
    }

    public void enableAccount(AccountVerificationToken token) {
        String username = token.getUser().getUsername();
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -&amp;gt; new ActivationException("User not found with username: " + username));
        user.setAccountStatus(true);
        userRepository.save(user);
    }

    public boolean isLoggedIn() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        return !(authentication instanceof AnonymousAuthenticationToken) &amp;amp;&amp;amp; authentication.isAuthenticated();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: Post Service 🌎
&lt;/h2&gt;

&lt;p&gt;Let's cover the subreddit service our application will have. Inside &lt;strong&gt;com.your-name.backend.services&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostService: Hold the logic for mapping data to and from DTO's, getting all post's, getting specific posts's, and adding post's.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.github.marlonlom.utilities.timeago.TimeAgo;
import com.maxicb.backend.dto.PostRequest;
import com.maxicb.backend.dto.PostResponse;
import com.maxicb.backend.exception.PostNotFoundException;
import com.maxicb.backend.exception.SubredditNotFoundException;
import com.maxicb.backend.exception.UserNotFoundException;
import com.maxicb.backend.model.*;
import com.maxicb.backend.repository.*;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@Service
@AllArgsConstructor
@Transactional
public class PostService {

    private final PostRepository postRepository;
    private final SubredditRepository subredditRepository;
    private final UserRepository userRepository;
    private final CommentRepository commentRepository;
    private final AuthService authService;
    private final VoteRepository voteRepository;

    private boolean checkVoteType(Post post, VoteType voteType) {
        if(authService.isLoggedIn()) {
            Optional&amp;lt;Vote&amp;gt; voteForPostForUser = voteRepository.findTopByPostAndUserOrderByVoteIdDesc(post, authService.getCurrentUser());
            return voteForPostForUser.filter(vote -&amp;gt; vote.getVoteType().equals(voteType)).isPresent();
        }
        return false;
    }

    private PostResponse mapToResponse(Post post) {
        return PostResponse.builder()
                .postId(post.getPostId())
                .postTitle(post.getPostTitle())
                .url(post.getUrl())
                .description(post.getDescription())
                .userName(post.getUser().getUsername())
                .subredditName(post.getSubreddit().getName())
                .voteCount(post.getVoteCount())
                .commentCount(commentRepository.findByPost(post).size())
                .duration(TimeAgo.using(post.getCreationDate().toEpochMilli()))
                .upVote(checkVoteType(post, VoteType.UPVOTE))
                .downVote(checkVoteType(post, VoteType.DOWNVOTE))
                .build();
    }

    private Post mapToPost(PostRequest postRequest) {
        Subreddit subreddit = subredditRepository.findByName(postRequest.getSubredditName())
                .orElseThrow(() -&amp;gt; new SubredditNotFoundException(postRequest.getSubredditName()));
        Post newPost = Post.builder()
                .postTitle(postRequest.getPostTitle())
                .url(postRequest.getUrl())
                .description(postRequest.getDescription())
                .voteCount(0)
                .user(authService.getCurrentUser())
                .creationDate(Instant.now())
                .subreddit(subreddit)
                .build();
        subreddit.getPosts().add(newPost);
        return newPost;
    }

    public PostResponse save(PostRequest postRequest) {
        return mapToResponse(postRepository.save(mapToPost(postRequest)));
    }

    public List&amp;lt;PostResponse&amp;gt; getAllPost() {
        return StreamSupport
                .stream(postRepository.findAll().spliterator(), false)
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    public PostResponse findByID (Long id) {
        Post post = postRepository.findById(id)
                .orElseThrow(() -&amp;gt; new PostNotFoundException("Post not found with id: " + id));
        return mapToResponse(post);
    }

    public List&amp;lt;PostResponse&amp;gt; getPostsBySubreddit(Long id) {
        Subreddit subreddit = subredditRepository.findById(id)
                .orElseThrow(() -&amp;gt; new SubredditNotFoundException("Subreddit not found with id: " + id));
        return subreddit.getPosts().stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }

    public List&amp;lt;PostResponse&amp;gt; getPostsByUsername(String username) {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -&amp;gt; new UserNotFoundException("User not found with username: " + username));
        return postRepository.findByUser(user).stream()
                .map(this::mapToResponse)
                .collect(Collectors.toList());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: READ &amp;amp;&amp;amp; CREATE Post Endpoint's 🌐
&lt;/h2&gt;

&lt;p&gt;Let's cover the post controller our application will have. Inside &lt;strong&gt;com.your-name.backend.controller&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PostController: Hold the logic for fetching creating post's, fetching all post's, and specific post's based on user, and subreddit.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.controller;

import com.maxicb.backend.dto.PostRequest;
import com.maxicb.backend.dto.PostResponse;
import com.maxicb.backend.service.PostService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/api/posts")
@AllArgsConstructor
public class PostController {
    private final PostService postService;

    @PostMapping
    public ResponseEntity&amp;lt;Void&amp;gt; addPost(@RequestBody PostRequest postRequest) {
        postService.save(postRequest);
        return new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.CREATED);
    }

    @GetMapping
    public ResponseEntity&amp;lt;List&amp;lt;PostResponse&amp;gt;&amp;gt; getAllPost() {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.getAllPost(), HttpStatus.OK);
    }

    @GetMapping("{id}")
    public ResponseEntity&amp;lt;PostResponse&amp;gt; getPostByID(@PathVariable Long id) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.findByID(id), HttpStatus.OK);
    }

    @GetMapping("/sub/{id}")
    public ResponseEntity&amp;lt;List&amp;lt;PostResponse&amp;gt;&amp;gt; getPostsBySubreddit(@PathVariable Long id) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.getPostsBySubreddit(id), HttpStatus.OK);
    }

    @GetMapping("/user/{name}")
    public ResponseEntity&amp;lt;List&amp;lt;PostResponse&amp;gt;&amp;gt; getPostsByUsername(@PathVariable String username) {
        return new ResponseEntity&amp;lt;&amp;gt;(postService.getPostsByUsername(username), HttpStatus.OK);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Updated application.properties ⚙
&lt;/h2&gt;

&lt;p&gt;To alleviate having to create a new user, and walking through the registration, and creating of subreddit to test the newly added logic we are going to update the application.properties to persist our data. Inside &lt;strong&gt;main.resources&lt;/strong&gt; update your application.properties file to match below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Database Properties
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=admin
spring.datasource.initialization-mode=always
# Changing this from create-drop to update
# Allows us to persist the database rather than
# Dropping it each time the application is ran
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
# Redis Properties
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
# Mail Properties
spring.mail.host=smtp.mailtrap.io
spring.mail.port=25
spring.mail.username=a08f0bfd316af9
spring.mail.password=ce1b93c770fc96
spring.mail.protocol=smtp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" title="Successful Run" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no error's in the console you can test you post creation logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/posts" rel="noopener noreferrer"&gt;http://localhost:8080/api/posts&lt;/a&gt;&lt;/strong&gt; with the following data. You will still have to follow the same steps covered in the previous parts to login to an account to make post's, as well as create a subreddit and provide a valid name.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "postTitle": "Testing Post",
    "url": "HEREEEE",
    "description": "HEREEEE",
    "subredditName": "/r/NAME"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this article we added the CREATE &amp;amp;&amp;amp; READ endpoints for post's, updated our application properties and added new exception's.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Follow to get informed when part seven is released, where we will cover the Create/Read operations for comments! If you have any questions be sure to leave a comment!
&lt;/h3&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 5</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Mon, 03 Aug 2020 16:27:09 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-5-2h8j</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-5-2h8j</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 5
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 5 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWT Validation&lt;/li&gt;
&lt;li&gt;JWT Filtering&lt;/li&gt;
&lt;li&gt;Update Auth Service&lt;/li&gt;
&lt;li&gt;Subreddit DTO&lt;/li&gt;
&lt;li&gt;Subreddit Service&lt;/li&gt;
&lt;li&gt;READ Subreddit Endpoint&lt;/li&gt;
&lt;li&gt;CREATE Subreddit Endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-4-4eam"&gt;Part 4&lt;/a&gt; we created the logic needed for JWT validation, updated our authentication service, and made our login endpoint's!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: JWT Validation 🔐
&lt;/h2&gt;

&lt;p&gt;Let's cover our JWT validation logic we will need. Inside &lt;strong&gt;com.your-name.backend.security&lt;/strong&gt; we will update the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWTProvider: Handles all of the logic for loading the keystore, gathering public/private keys, generating JWT, token validation, and gathering user information.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.security;

import com.maxicb.backend.exception.ActivationException;
import io.jsonwebtoken.Claims;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;

import io.jsonwebtoken.Jwts;
import static io.jsonwebtoken.Jwts.parserBuilder;

@Service
public class JWTProvider {
    private KeyStore keystore;

    @PostConstruct
    public void init() {
        try {
            keystore = KeyStore.getInstance("JKS");
            InputStream resourceStream = getClass().getResourceAsStream("/reddit.jks");
            keystore.load(resourceStream, "secret".toCharArray());
        } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
            throw new ActivationException("Exception occured while loading keystore");
        }
    }

    public String generateToken(Authentication authentication) {
        org.springframework.security.core.userdetails.User princ = (User) authentication.getPrincipal();
        return Jwts.builder().setSubject(princ.getUsername()).signWith(getPrivKey()).compact();
    }

    public boolean validateToken (String token) {
        parserBuilder().setSigningKey(getPubKey()).build().parseClaimsJws(token);
        return true;
    }

    private PrivateKey getPrivKey () {
        try {
            return (PrivateKey) keystore.getKey("vox", "secret".toCharArray());
        } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
            throw new ActivationException("Exception occurred while retrieving public key");
        }
    }

    private PublicKey getPubKey () {
        try {
            return keystore.getCertificate("vox").getPublicKey();
        } catch(KeyStoreException e) {
            throw new ActivationException("Exception occurred retrieving public key");
        }
    }

    public String getNameFromJWT(String token) {
        Claims claims = parserBuilder()
                .setSigningKey(getPubKey())
                .build()
                .parseClaimsJws(token)
                .getBody();
        return claims.getSubject();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: JWT Filtering 🗄
&lt;/h2&gt;

&lt;p&gt;Let's cover our JWT filtering logic we will need. Inside &lt;strong&gt;com.your-name.backend.security&lt;/strong&gt; we will update the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWTAuthFilter: Handles loading JWT from request, and filtering.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class JWTAuthFilter extends OncePerRequestFilter {
    @Autowired
    private JWTProvider jwtProvider;
    @Qualifier("inMemoryUserDetailsManager")
    @Autowired
    private UserDetailsService userDetailsService;

    private String getTokenFromRequest (HttpServletRequest request) {
        String bearer = request.getHeader("Authorization");
        if(StringUtils.hasText(bearer) &amp;amp;&amp;amp; bearer.startsWith("Bearer ")) {
            return bearer.substring(7);
        }
        return bearer;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
        String JWT = getTokenFromRequest(httpServletRequest);

        if (StringUtils.hasText(JWT) &amp;amp;&amp;amp; jwtProvider.validateToken(JWT)) {
            String username = jwtProvider.getNameFromJWT(JWT);

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
                    userDetails,
                    null,
                    userDetails.getAuthorities());
            auth.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
            SecurityContextHolder.getContext().setAuthentication(auth);
        }
        filterChain.doFilter(httpServletRequest, httpServletResponse);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Updated Security Configuration 💂‍♀️
&lt;/h2&gt;

&lt;p&gt;Let's cover our JWT validation logic we will need. Inside &lt;strong&gt;com.your-name.backend.config&lt;/strong&gt; we will update the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security: We need to implement our newly created JWT Filter so that it will run first.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.config;

import com.maxicb.backend.security.JWTAuthFilter;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@AllArgsConstructor
public class Security extends WebSecurityConfigurerAdapter {

    UserDetailsService userDetailsService;
    JWTAuthFilter jwtAuthFilter;

    @Autowired
    public void configureGlobalConfig(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/auth/**")
                .permitAll()
                .anyRequest()
                .authenticated();
        httpSecurity.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: Updated Auth Service 💂‍♀️
&lt;/h2&gt;

&lt;p&gt;Let's cover our JWT validation logic we will need. Inside &lt;strong&gt;com.your-name.backend.service&lt;/strong&gt; we will update the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthService: We need to implement logic to get the current user information.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.dto.AuthResponse;
import com.maxicb.backend.dto.LoginRequest;
import com.maxicb.backend.dto.RegisterRequest;
import com.maxicb.backend.exception.ActivationException;
import com.maxicb.backend.model.AccountVerificationToken;
import com.maxicb.backend.model.NotificationEmail;
import com.maxicb.backend.model.User;
import com.maxicb.backend.repository.TokenRepository;
import com.maxicb.backend.repository.UserRepository;
import com.maxicb.backend.security.JWTProvider;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Optional;
import java.util.UUID;

import static com.maxicb.backend.config.Constants.EMAIL_ACTIVATION;

@Service
@AllArgsConstructor

public class AuthService {

    UserRepository userRepository;
    PasswordEncoder passwordEncoder;
    TokenRepository tokenRepository;
    MailService mailService;
    MailBuilder mailBuilder;
    AuthenticationManager authenticationManager;
    JWTProvider jwtProvider;

    @Transactional
    public void register(RegisterRequest registerRequest) {
        User user = new User();
        user.setUsername(registerRequest.getUsername());
        user.setEmail(registerRequest.getEmail());
        user.setPassword(encodePassword(registerRequest.getPassword()));
        user.setCreationDate(Instant.now());
        user.setAccountStatus(false);

        userRepository.save(user);

        String token = generateToken(user);
        String message = mailBuilder.build("Welcome to React-Spring-Reddit Clone. " +
                "Please visit the link below to activate you account : " + EMAIL_ACTIVATION + "/" + token);
        mailService.sendEmail(new NotificationEmail("Please Activate Your Account", user.getEmail(), message));
    }

    @Transactional(readOnly = true)
    public User getCurrentUser() {
        org.springframework.security.core.userdetails.User principal = (org.springframework.security.core.userdetails.User) SecurityContextHolder.
                getContext().getAuthentication().getPrincipal();
        return userRepository.findByUsername(principal.getUsername())
                .orElseThrow(() -&amp;gt; new UsernameNotFoundException("User not found with username: " + principal.getUsername()));
    }

    public AuthResponse login (LoginRequest loginRequest) {
        Authentication authenticate = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(), loginRequest.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        String authToken = jwtProvider.generateToken(authenticate);
        return new AuthResponse(authToken, loginRequest.getUsername());
    }

    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    private String generateToken(User user) {
        String token = UUID.randomUUID().toString();
        AccountVerificationToken verificationToken = new AccountVerificationToken();
        verificationToken.setToken(token);
        verificationToken.setUser(user);
        tokenRepository.save(verificationToken);
        return token;
    }

    public void verifyToken(String token) {
        Optional&amp;lt;AccountVerificationToken&amp;gt; verificationToken = tokenRepository.findByToken(token);
        verificationToken.orElseThrow(() -&amp;gt; new ActivationException("Invalid Activation Token"));
        enableAccount(verificationToken.get());
    }

    public void enableAccount(AccountVerificationToken token) {
        String username = token.getUser().getUsername();
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -&amp;gt; new ActivationException("User not found with username: " + username));
        user.setAccountStatus(true);
        userRepository.save(user);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Subreddit DTO 📨
&lt;/h2&gt;

&lt;p&gt;Let's cover the Subreddit DTO class we will need. Inside &lt;strong&gt;com.your-name.backend.dto&lt;/strong&gt; create the following class,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SubredditDTO: Defines the data that our backend will send/receive from the client during a subreddit requests.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SubredditDTO {
    private Long id;
    private String name;
    private String description;
    private Integer postCount;
    private Integer memberCount;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 6: Subreddit Exception 🚫
&lt;/h2&gt;

&lt;p&gt;Let's cover the subreddit not found exception our application will have. Inside &lt;strong&gt;com.your-name.backend.exception&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SubredditNotFoundException: Our custom exception handler for subreddit not found errors.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.exception;

public class SubredditNotFoundException extends RuntimeException {
    public SubredditNotFoundException(String message) {
        super(message);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 6: Subreddit Service 🌎
&lt;/h2&gt;

&lt;p&gt;Let's cover the subreddit service our application will have. Inside &lt;strong&gt;com.your-name.backend.services&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SubredditService: Hold the logic for mapping data to and from DTO, getting all subreddits, getting specific subreddits, and adding subreddits.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.dto.SubredditDTO;
import com.maxicb.backend.exception.SubredditNotFoundException;
import com.maxicb.backend.model.Subreddit;
import com.maxicb.backend.repository.SubredditRepository;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;

@Service
@AllArgsConstructor
public class SubredditService {

    private final SubredditRepository subredditRepository;
    private final AuthService authService;

    private SubredditDTO mapToDTO (Subreddit subreddit) {
        return SubredditDTO.builder()
                .id(subreddit.getId())
                .name(subreddit.getName())
                .description(subreddit.getDescription())
                .postCount(subreddit.getPosts().size())
                .build();

    }

    private Subreddit mapToSubreddit (SubredditDTO subredditDTO) {
        return Subreddit.builder().name("/r/" + subredditDTO.getName())
                .description(subredditDTO.getDescription())
                .user(authService.getCurrentUser())
                .creationDate(Instant.now())
                .build();

    }

    @Transactional(readOnly = true)
    public List&amp;lt;SubredditDTO&amp;gt; getAll() {
        return StreamSupport
                .stream(subredditRepository.findAll().spliterator(), false)
                .map(this::mapToDTO)
                .collect(Collectors.toList());
    }

    @Transactional
    public SubredditDTO save(SubredditDTO subredditDTO) {
        Subreddit subreddit = subredditRepository.save(mapToSubreddit(subredditDTO));
        subredditDTO.setId(subreddit.getId());
        return subredditDTO;
    }

    @Transactional(readOnly = true)
    public SubredditDTO getSubreddit(Long id) {
        Subreddit subreddit = subredditRepository.findById(id)
                .orElseThrow(() -&amp;gt; new SubredditNotFoundException("Subreddit not found with id -" + id));
        return mapToDTO(subreddit);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 7: READ &amp;amp;&amp;amp; CREATE Subreddit Endpoint's 🌐
&lt;/h2&gt;

&lt;p&gt;Let's cover the subreddit controller our application will have. Inside &lt;strong&gt;com.your-name.backend.controller&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SubredditController: Hold the logic for fetching creating subreddits, fetching all subreddits, and specific subreddits.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.controller;

import com.maxicb.backend.dto.SubredditDTO;
import com.maxicb.backend.service.SubredditService;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

@RestController
@RequestMapping("/api/subreddit")
@AllArgsConstructor
public class SubredditController {

    SubredditService subredditService;

    @GetMapping
    public List&amp;lt;SubredditDTO&amp;gt; getAllSubreddits () {
        return subredditService.getAll();
    }

    @GetMapping("/{id}")
    public SubredditDTO getSubreddit(@PathVariable Long id) {
        return subredditService.getSubreddit(id);
    }

    @PostMapping
    public SubredditDTO addSubreddit(@RequestBody @Valid SubredditDTO subredditDTO) {
        return subredditService.save(subredditDTO);
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZgbYnXkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZgbYnXkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mcnzflm8vjwnvjcx40sh.PNG" alt="Alt Text" title="Successful Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no error's in the console you can test you registration logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/auth/register"&gt;http://localhost:8080/api/auth/register&lt;/a&gt;&lt;/strong&gt; with the following data
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "username": "test",
    "email": "test1@test.com",
    "password": "test12345"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once you recieve a 200 OK status back you can check you mailtrap.io inbox to find the activation email that was sent. The link should look similar to &lt;a href="http://localhost:8080/api/auth/verify/%7Btoken%7D"&gt;http://localhost:8080/api/auth/verify/{token}&lt;/a&gt;, &lt;strong&gt;be sure to omit the &amp;amp;lt&lt;/strong&gt; from the end of the link. Navigation to the link will activate the account, and you should see "Account Activated" displayed as a response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After activating your account you can test you login logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/auth/login"&gt;http://localhost:8080/api/auth/login&lt;/a&gt;&lt;/strong&gt; with the following data&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "username": "test",
    "password": "test12345"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After logging in you should see a response similar to below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "authenticationToken": {real_long_token},
    "username": "test"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Add the token to the API testing tool you use as the authorization header, set as the Bearer Token type.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can now send a POST request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/subreddit/"&gt;http://localhost:8080/api/subreddit/&lt;/a&gt;&lt;/strong&gt; with the following data&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "name": "NAME",
    "description": "DESCRIPTION",
    "postCount": null
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You should recieve a 200 OK with the subreddit information back as a response, to ensure it was saved in the database you can send a GET request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/subreddit"&gt;http://localhost:8080/api/subreddit&lt;/a&gt;&lt;/strong&gt; and you should recieve the following data
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
        "id": 1,
        "name": "NAME",
        "description": "DESCRIPTION",
        "postCount": null
    }
]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this article we added our JWT validation, and filtering, updated our authentication services, and implemented the CREATE &amp;amp;&amp;amp; READ endpoints for subreddit's.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-6-5e33"&gt;Part 6&lt;/a&gt; is released, where we will cover the Create/Read operations for posts! If you have any questions be sure to leave a comment!
&lt;/h3&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 4</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Sun, 02 Aug 2020 16:27:42 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-4-4eam</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-4-4eam</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 4
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 4 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Information Service Implementation&lt;/li&gt;
&lt;li&gt;Update Security Configuration&lt;/li&gt;
&lt;li&gt;Authentication Response&lt;/li&gt;
&lt;li&gt;Login Request DTO&lt;/li&gt;
&lt;li&gt;Update Auth Service&lt;/li&gt;
&lt;li&gt;Creation of Java Key Store&lt;/li&gt;
&lt;li&gt;Creation of JWT&lt;/li&gt;
&lt;li&gt;Login Logic&lt;/li&gt;
&lt;li&gt;Login Endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n"&gt;Part 3&lt;/a&gt; we created the registration and account verification logic!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: User Information Service Implementation 😀
&lt;/h2&gt;

&lt;p&gt;Let's cover the user service implementation class we will need. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;service&lt;/strong&gt;, and add the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UserInformationServiceImpl: Is our interface that fetches user information from our PostgreSQL database.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.model.User;
import com.maxicb.backend.repository.UserRepository;
import lombok.AllArgsConstructor;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Collections;
import java.util.Optional;

@Service
@AllArgsConstructor
public class UserInformationServiceImpl implements UserDetailsService {
    UserRepository userRepository;

    private Collection&amp;lt;? extends GrantedAuthority&amp;gt; fetchAuths (String role) {
        return Collections.singletonList(new SimpleGrantedAuthority(role));
    }

    @Override
    @Transactional(readOnly = true)
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Optional&amp;lt;User&amp;gt; optionalUser = userRepository.findByUsername(s);
        User user = optionalUser.orElseThrow(() -&amp;gt; new UsernameNotFoundException("No user found with username: " + s));

        return new org.springframework.security.core.userdetails.User(user.getUsername(),
                user.getPassword(),
                user.isAccountStatus(),
                true,
                true,
                true,
                fetchAuths("USER"));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Updated Security Configuration 🎟
&lt;/h2&gt;

&lt;p&gt;Let's cover the security config class we will need to update. Inside &lt;strong&gt;com.your-name.backend.config&lt;/strong&gt; update the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security: Handles the security configuration for the whole application, handles encoding the password before storing it into the database, and fetching user information.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.config;

import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@EnableWebSecurity
@AllArgsConstructor
public class Security extends WebSecurityConfigurerAdapter {

    UserDetailsService userDetailsService;

    @Autowired
    public void configureGlobalConfig(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder.userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());
    }

    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/auth/**")
                .permitAll()
                .anyRequest()
                .authenticated();
    }

    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Authentication Response DTO
&lt;/h2&gt;

&lt;p&gt;Let's cover the Authentication Response DTO class we will need. Inside &lt;strong&gt;com.your-name.backend.dto&lt;/strong&gt; create the following class,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthResponse: Defines the data that our backend will send to the client for an authentication response.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class AuthResponse {
        private String authenticationToken;
        private String username;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: Login Request DTO
&lt;/h2&gt;

&lt;p&gt;Let's cover the Login Request DTO class we will need. Inside &lt;strong&gt;com.your-name.backend.dto&lt;/strong&gt; create the following class,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;LoginRequest: Defines the data that our backend will recieve from the client during a login request.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class LoginRequest {
    private String username;
    private String password;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Create Java Key Store
&lt;/h2&gt;

&lt;p&gt;Let's cover the java keystore we will need. Inside &lt;strong&gt;resources&lt;/strong&gt; place the keystore you will create after you are done.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java Keystore:
You can refer to the oracle docs for creating a keystore &lt;a href="https://docs.oracle.com/cd/E35976_01/server.740/es_admin/src/tadm_ssl_jetty_keystore.html"&gt;Here&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;Key store generation command
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  keytool -genkey -alias alias -keyalg RSA -keystore keystore.jks -keysize 2048
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure you are in a easily acessible directory when you run this command as it will create the keystore there, and you will need to place it inside your project.&lt;br&gt;
  Ensure you keep track of the password, and alias that you use as you will need it later within the code base.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 6: Create JWT
&lt;/h2&gt;

&lt;p&gt;Let's cover the JWT class we will need. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;security&lt;/strong&gt;, and add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JWTProvider: Handles all of the logic for loading the keystore, and generating JWT based on that.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.security;

import com.maxicb.backend.exception.ActivationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.security.*;
import java.security.cert.CertificateException;

import io.jsonwebtoken.Jwts;

@Service
public class JWTProvider {
    private KeyStore keystore;

    @PostConstruct
    public void init() {
        try {
            keystore = KeyStore.getInstance("JKS");
            InputStream resourceStream = getClass().getResourceAsStream("/keystore.jks");
            keystore.load(resourceStream, "password".toCharArray());
        } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) {
            throw new ActivationException("Exception occured while loading keystore");
        }
    }

    public String generateToken(Authentication authentication) {
        org.springframework.security.core.userdetails.User princ = (User) authentication.getPrincipal();
        return Jwts.builder().setSubject(princ.getUsername()).signWith(getPrivKey()).compact();
    }

    private PrivateKey getPrivKey () {
        try {
            return (PrivateKey) keystore.getKey("alias", "password".toCharArray());
        } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableKeyException e) {
            throw new ActivationException("Exception occurred while retrieving public key");
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 7: Update Auth Service
&lt;/h2&gt;

&lt;p&gt;Let's update out Authentication Service class to add login functionality. Inside &lt;strong&gt;com.your-name.backend.service&lt;/strong&gt; update the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthService: We are adding the login logic to our authentication service.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.service;

import com.maxicb.backend.dto.AuthResponse;
import com.maxicb.backend.dto.LoginRequest;
import com.maxicb.backend.dto.RegisterRequest;
import com.maxicb.backend.exception.ActivationException;
import com.maxicb.backend.model.AccountVerificationToken;
import com.maxicb.backend.model.NotificationEmail;
import com.maxicb.backend.model.User;
import com.maxicb.backend.repository.TokenRepository;
import com.maxicb.backend.repository.UserRepository;
import com.maxicb.backend.security.JWTProvider;
import lombok.AllArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Optional;
import java.util.UUID;

import static com.maxicb.backend.config.Constants.EMAIL_ACTIVATION;

@Service
@AllArgsConstructor

public class AuthService {

    UserRepository userRepository;
    PasswordEncoder passwordEncoder;
    TokenRepository tokenRepository;
    MailService mailService;
    MailBuilder mailBuilder;
    AuthenticationManager authenticationManager;
    JWTProvider jwtProvider;

    @Transactional
    public void register(RegisterRequest registerRequest) {
        User user = new User();
        user.setUsername(registerRequest.getUsername());
        user.setEmail(registerRequest.getEmail());
        user.setPassword(encodePassword(registerRequest.getPassword()));
        user.setCreationDate(Instant.now());
        user.setAccountStatus(false);

        userRepository.save(user);

        String token = generateToken(user);
        String message = mailBuilder.build("Welcome to React-Spring-Reddit Clone. " +
                "Please visit the link below to activate you account : " + EMAIL_ACTIVATION + "/" + token);
        mailService.sendEmail(new NotificationEmail("Please Activate Your Account", user.getEmail(), message));
    }

    public AuthResponse login (LoginRequest loginRequest) {
        Authentication authenticate = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getUsername(), loginRequest.getPassword()));
        SecurityContextHolder.getContext().setAuthentication(authenticate);
        String authToken = jwtProvider.generateToken(authenticate);
        return new AuthResponse(authToken, loginRequest.getUsername());
    }

    private String encodePassword(String password) {
        return passwordEncoder.encode(password);
    }

    private String generateToken(User user) {
        String token = UUID.randomUUID().toString();
        AccountVerificationToken verificationToken = new AccountVerificationToken();
        verificationToken.setToken(token);
        verificationToken.setUser(user);
        tokenRepository.save(verificationToken);
        return token;
    }

    public void verifyToken(String token) {
        Optional&amp;lt;AccountVerificationToken&amp;gt; verificationToken = tokenRepository.findByToken(token);
        verificationToken.orElseThrow(() -&amp;gt; new ActivationException("Invalid Activation Token"));
        enableAccount(verificationToken.get());
    }

    public void enableAccount(AccountVerificationToken token) {
        String username = token.getUser().getUsername();
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -&amp;gt; new ActivationException("User not found with username: " + username));
        user.setAccountStatus(true);
        userRepository.save(user);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 8: Login Endpoint
&lt;/h2&gt;

&lt;p&gt;Let's update our Auth Controller class to add login endpoint. Inside &lt;strong&gt;com.your-name.backend.controller&lt;/strong&gt; update the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthController: Defines the different endpoints for registering, activating, and logging in a user.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.controller;

import com.maxicb.backend.dto.AuthResponse;
import com.maxicb.backend.dto.LoginRequest;
import com.maxicb.backend.dto.RegisterRequest;
import com.maxicb.backend.service.AuthService;
import lombok.AllArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
@AllArgsConstructor
public class AuthController {

    AuthService authService;

    @PostMapping("/register")
    public ResponseEntity register(@RequestBody RegisterRequest registerRequest) {
        authService.register(registerRequest);
        return new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.OK);
    }

    @GetMapping("/verify/{token}")
    public ResponseEntity verify(@PathVariable String token) {
        authService.verifyToken(token);
        return new ResponseEntity&amp;lt;&amp;gt;("Account Activated", HttpStatus.OK);
    }

    @PostMapping("/login")
    public AuthResponse register(@RequestBody LoginRequest loginRequest) {
        return authService.login(loginRequest);
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZgbYnXkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZgbYnXkN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/mcnzflm8vjwnvjcx40sh.PNG" alt="Alt Text" title="Successful Run"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no error's in the console you can test you registration logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/auth/register"&gt;http://localhost:8080/api/auth/register&lt;/a&gt;&lt;/strong&gt; with the following data
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "username": "test",
    "email": "test1@test.com",
    "password": "test12345"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once you recieve a 200 OK status back you can check you mailtrap.io inbox to find the activation email that was sent. The link should look similar to &lt;a href="http://localhost:8080/api/auth/verify/%7Btoken%7D"&gt;http://localhost:8080/api/auth/verify/{token}&lt;/a&gt;, &lt;strong&gt;be sure to omit the &amp;amp;lt&lt;/strong&gt; from the end of the link. Navigation to the link will activate the account, and you should see "Account Activated" displayed as a response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After activating your account you can test you login logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/auth/login"&gt;http://localhost:8080/api/auth/login&lt;/a&gt;&lt;/strong&gt; with the following data&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "username": "test",
    "password": "test12345"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After logging in you should see a response similar to below
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "authenticationToken": {real_long_token},
    "username": "test"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;In this article we added our JWT token generation, login logic, and login endpoint.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-5-2h8j"&gt;Part 5&lt;/a&gt;
&lt;/h2&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 3</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Tue, 28 Jul 2020 14:00:16 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 3
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 3 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;What are we building in this part?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Registration Logic&lt;/li&gt;
&lt;li&gt;Registration Endpoint&lt;/li&gt;
&lt;li&gt;Password Encoding&lt;/li&gt;
&lt;li&gt;Activation Emails&lt;/li&gt;
&lt;li&gt;Verification/Activation Endpoint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-2-446l"&gt;Part 2&lt;/a&gt; we created all of entities and repositories needed within our backend!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Spring Security 🔒
&lt;/h2&gt;

&lt;p&gt;Let's cover the different configuration classes we will need. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;config&lt;/strong&gt;, and add the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security: Handles the security configuration for the whole application, and handles encoding the password before storing it into the database.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;package com.maxicb.backend.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;

    @EnableWebSecurity
    public class Security extends WebSecurityConfigurerAdapter {

        @Override
        public void configure(HttpSecurity httpSecurity) throws Exception {
            httpSecurity.csrf().disable()
                    .authorizeRequests()
                    .antMatchers("/api/auth/**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();
        }

        @Bean
        PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Constants: Defines the link to the activation endpoint that will be sent inside the account activation email.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.config;

    import lombok.experimental.UtilityClass;

    @UtilityClass
    public class Constants {
        public static final String EMAIL_ACTIVATION = "http://localhost:8080/api/auth/verify";
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Registration Request Data Transfer Object - DTO 📃
&lt;/h2&gt;

&lt;p&gt;Let's cover the different DTO classes we will need. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;dto&lt;/strong&gt;, and add the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;RegisterRequest: Defines the data that our backend will recieve from the client during a registration request.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.dto;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class RegisterRequest {
        private String username;
        private String email;
        private String password;
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 3: Activation Exception Creation 📛
&lt;/h2&gt;

&lt;p&gt;Let's cover all of the custom exceptions our application will have. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;exception&lt;/strong&gt;, and add the following classes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ActivationException: Custom exception to handle errors when sending users activation emails
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.exception;

    public class ActivationException extends RuntimeException {
        public ActivationException(String message) {
            super(message);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: Email Builder 🛠
&lt;/h2&gt;

&lt;p&gt;Let's cover all of the different email building classes our application will have. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;service&lt;/strong&gt;, and add the following classes.&lt;/p&gt;

&lt;p&gt;We also need to add the @EnableAsync annotation to our BackendApplication.java class to reduce the amount of time the user is waiting during registration. The reason this is needed is due to the registration endpoint hanging when sending the account activation email. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BackendApplication - Updated:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.scheduling.annotation.EnableAsync;

    @SpringBootApplication
    @EnableAsync
    public class BackendApplication {

        public static void main(String[] args) {
            SpringApplication.run(BackendApplication.class, args);
        }

    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;MailBuilder: Holds the logic to create our email using a HTML template we will create later.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.service;

    import lombok.AllArgsConstructor;
    import org.springframework.stereotype.Service;
    import org.thymeleaf.TemplateEngine;
    import org.thymeleaf.context.Context;

    @Service
    @AllArgsConstructor
    public class MailBuilder {

        TemplateEngine templateEngine;

        String build(String message) {
            Context context = new Context();
            context.setVariable("body", message);
            return templateEngine.process("mailTemplate", context);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;MailService: Holds the logic to send a user an account activation email.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.service;

    import com.maxicb.backend.exception.ActivationException;
    import com.maxicb.backend.model.NotificationEmail;
    import lombok.AllArgsConstructor;
    import org.springframework.mail.MailException;
    import org.springframework.mail.javamail.JavaMailSender;
    import org.springframework.mail.javamail.MimeMessageHelper;
    import org.springframework.mail.javamail.MimeMessagePreparator;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Service;

    @Service
    @AllArgsConstructor

    public class MailService {

        JavaMailSender javaMailSender;
        MailBuilder mailBuilder;

        @Async
        void sendEmail(NotificationEmail notificationEmail) {
            MimeMessagePreparator messagePreparator = mimeMessage -&amp;gt; {
                MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage);
                messageHelper.setFrom("activation@redditclone.com");
                messageHelper.setTo(notificationEmail.getRecepient());
                messageHelper.setSubject(notificationEmail.getSubject());
                messageHelper.setText(mailBuilder.build(notificationEmail.getBody()));
            };
            try {
                javaMailSender.send(messagePreparator);
                System.out.println("Activation Email Sent");
            } catch (MailException e) {
                throw new ActivationException("Error sending activation email to " + notificationEmail.getRecepient());
            }
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Email Template 📧
&lt;/h2&gt;

&lt;p&gt;Let's add the HTML email template our application will use for account activation. Inside &lt;strong&gt;resources.templates&lt;/strong&gt; create a new file called &lt;strong&gt;mailTemplate.html&lt;/strong&gt;, and add the following template.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"&amp;gt;
&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;span th:text="${body}"&amp;gt;&amp;lt;/span&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 6: Authentication Service 🗝
&lt;/h2&gt;

&lt;p&gt;Let's cover all of the different authentication services our application will have. Inside &lt;strong&gt;com.your-name.backend.services&lt;/strong&gt; add the following class.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthService: Holds the logic to register a user and store them inside the database, encoding of users passwords, verifying tokens, and enabling of accounts.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.service;

    import com.maxicb.backend.dto.RegisterRequest;
    import com.maxicb.backend.exception.ActivationException;
    import com.maxicb.backend.model.AccountVerificationToken;
    import com.maxicb.backend.model.NotificationEmail;
    import com.maxicb.backend.model.User;
    import com.maxicb.backend.repository.TokenRepository;
    import com.maxicb.backend.repository.UserRepository;
    import lombok.AllArgsConstructor;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;

    import java.time.Instant;
    import java.util.Optional;
    import java.util.UUID;

    import static com.maxicb.backend.config.Constants.EMAIL_ACTIVATION;

    @Service
    @AllArgsConstructor

    public class AuthService {

        UserRepository userRepository;
        PasswordEncoder passwordEncoder;
        TokenRepository tokenRepository;
        MailService mailService;
        MailBuilder mailBuilder;

        @Transactional
        public void register(RegisterRequest registerRequest) {
            User user = new User();
            user.setUsername(registerRequest.getUsername());
            user.setEmail(registerRequest.getEmail());
            user.setPassword(encodePassword(registerRequest.getPassword()));
            user.setCreationDate(Instant.now());
            user.setAccountStatus(false);

            userRepository.save(user);

            String token = generateToken(user);
            String message = mailBuilder.build("Welcome to React-Spring-Reddit Clone. " +
                    "Please visit the link below to activate you account : " + EMAIL_ACTIVATION + "/" + token);
            mailService.sendEmail(new NotificationEmail("Please Activate Your Account", user.getEmail(), message));
        }

        private String encodePassword(String password) {
            return passwordEncoder.encode(password);
        }

        private String generateToken(User user) {
            String token = UUID.randomUUID().toString();
            AccountVerificationToken verificationToken = new AccountVerificationToken();
            verificationToken.setToken(token);
            verificationToken.setUser(user);
            tokenRepository.save(verificationToken);
            return token;
        }

        public void verifyToken(String token) {
            Optional&amp;lt;AccountVerificationToken&amp;gt; verificationToken = tokenRepository.findByToken(token);
            verificationToken.orElseThrow(() -&amp;gt; new ActivationException("Invalid Activation Token"));
            enableAccount(verificationToken.get());
        }

        public void enableAccount(AccountVerificationToken token) {
            String username = token.getUser().getUsername();
            User user = userRepository.findByUsername(username)
                    .orElseThrow(() -&amp;gt; new ActivationException("User not found with username: " + username));
            user.setAccountStatus(true);
            userRepository.save(user);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 7: Authentication Controller 🌐
&lt;/h2&gt;

&lt;p&gt;Let's add the authentication controller our application will use. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;controller&lt;/strong&gt;, and add the following classes..&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AuthController: Defines the different endpoints for registering a user, and activating account's when user's visit the activation link sent in the email.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.controller;

    import com.maxicb.backend.dto.RegisterRequest;
    import com.maxicb.backend.service.AuthService;
    import lombok.AllArgsConstructor;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.web.bind.annotation.*;

    @RestController
    @RequestMapping("/api/auth")
    @AllArgsConstructor
    public class AuthController {

        AuthService authService;

        @PostMapping("/register")
        public ResponseEntity register(@RequestBody RegisterRequest registerRequest) {
            authService.register(registerRequest);
            return new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.OK);
        }

        @GetMapping("/verify/{token}")
        public ResponseEntity verify(@PathVariable String token) {
            authService.verifyToken(token);
            return new ResponseEntity&amp;lt;&amp;gt;("Account Activated", HttpStatus.OK);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmcnzflm8vjwnvjcx40sh.PNG" title="Successful Run" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If there are no error's in the console you can test you registration logic by sending a post request to &lt;strong&gt;&lt;a href="http://localhost:8080/api/auth/register" rel="noopener noreferrer"&gt;http://localhost:8080/api/auth/register&lt;/a&gt;&lt;/strong&gt; with the following data
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "username": "test",
    "email": "test1@test.com",
    "password": "test12345"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Once you recieve a 200 OK status back you can check you mailtrap.io inbox to find the activation email that was sent. The link should look similar to &lt;a href="http://localhost:8080/api/auth/verify/%7Btoken%7D" rel="noopener noreferrer"&gt;http://localhost:8080/api/auth/verify/{token}&lt;/a&gt;, &lt;strong&gt;be sure to omit the &amp;amp;lt&lt;/strong&gt; from the end of the link. Navigation to the link will activate the account, and you should see "Account Activated" displayed as a response.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In this article we added Spring Security, user password encoding, sending account activation emails, and created the logic and endpoints to handle account registration, and activation. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After creating all of the different classes, and writing all of the code your project structure should look similar to below&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh0z10usvpjfy9uxf6fxm.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fh0z10usvpjfy9uxf6fxm.PNG" title="Project Structure" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Next &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-4-4eam"&gt;Part 4&lt;/a&gt;
&lt;/h2&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 2</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Mon, 27 Jul 2020 14:03:23 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-2-446l</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-2-446l</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 2
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to Part 2 of creating a Reddit clone using Spring Boot, and React.&lt;/p&gt;

&lt;p&gt;In &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-1-1c22"&gt;Part 1&lt;/a&gt; we initialized our project, and added all of the dependencies we will need. In this article we will cover creating all of the entities and repositories we will need to complete our backend!&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Creating Domain Entities 📝
&lt;/h2&gt;

&lt;p&gt;Let's cover all of the different domain entities our application will have. Inside &lt;strong&gt;com.your-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;models&lt;/strong&gt;, and add the following classes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: We installed Lombok as a dependency in part 1. We will be using varying Lombok Annotations throughout the development process. To access these annotations you will have to enable Annotation Processing in your IDE. For further instructions on this, you can view the Setting up Lombok guide here - &lt;a href="https://www.baeldung.com/lombok-ide" rel="noopener noreferrer"&gt;https://www.baeldung.com/lombok-ide&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: In some cases you may need to add the following dependency to your pom.xml file for field validation&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;spring-boot-starter-validation&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;User: Have a unique userId, a username, password, emailAddress, creationDate, accountStatus
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import javax.persistence.*;
    import javax.validation.constraints.Email;
    import javax.validation.constraints.NotBlank;
    import java.time.Instant;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Table(name = "users")
    @Entity
    public class User {
        @Id
        @SequenceGenerator(name = "USER_GEN", sequenceName = "SEQ_USER", allocationSize = 1)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "USER_GEN")
        private Long userId;
        @NotBlank(message = "Username is required")
        private String username;
        @NotBlank(message = "Password is required")
        private String password;
        @Email
        @NotBlank(message = "Email is required")
        private String email;
        private Instant creationDate;
        private boolean accountStatus;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Post: Have a unique postId, postName, url, description, voteCount, user, creationDate, subreddit
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import org.springframework.lang.Nullable;

    import javax.persistence.*;
    import javax.validation.constraints.NotBlank;
    import java.time.Instant;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    public class Post {
        @Id
        @SequenceGenerator(name = "POST_GEN", sequenceName = "SEQ_POST", allocationSize = 1)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "POST_GEN")
        private Long postId;
        @NotBlank(message = "Post Title is required")
        private String postTitle;
        @Nullable
        private String url;
        @Nullable
        @Lob
        private String description;
        private Integer voteCount;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "userId", referencedColumnName = "userId")
        private User user;
        private Instant creationDate;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "id", referencedColumnName = "id")
        private Subreddit subreddit;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Subreddit: Have a unique id, name, description, posts, creationDate, users
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import javax.persistence.*;
    import javax.validation.constraints.NotBlank;
    import java.time.Instant;
    import java.util.List;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    public class Subreddit {
        @Id
        @SequenceGenerator(name = "SUB_GEN", sequenceName = "SEQ_SUB", allocationSize = 1)
        @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SUB_GEN")
        private Long id;
        @NotBlank(message = "Subreddit name is required")
        private String name;
        @NotBlank(message = "Subreddit description is required")
        private String description;
        @OneToMany(fetch = FetchType.LAZY)
        private List&amp;lt;Post&amp;gt; posts;
        private Instant creationDate;
        @ManyToOne(fetch = FetchType.LAZY)
        private User user;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Vote: Have a unique id, post, user
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import javax.persistence.*;
    import javax.validation.constraints.NotNull;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    public class Vote {
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        private Long voteId;
        private VoteType voteType;
        @NotNull
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "postId", referencedColumnName = "postId")
        private Post post;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "userId", referencedColumnName = "userId")
        private User user;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Comment: Have a unique id, text, post, creationDate, user
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import javax.persistence.*;
    import javax.validation.constraints.NotEmpty;
    import java.time.Instant;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Entity
    public class Comment {
        @Id
        @GeneratedValue(strategy = GenerationType.SEQUENCE)
        private Long id;
        @NotEmpty
        private String text;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "postId", referencedColumnName = "postId")
        private Post post;
        private Instant creationDate;
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "userId", referencedColumnName = "userId")
        private User user;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;VoteType ENUM: Upvote, Downvote
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    public enum VoteType {
        UPVOTE(1), DOWNVOTE(-1);

        VoteType(int direction) {}
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;AccountVerificationToken: Have a unique id, token, user, expirationDate
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    import javax.persistence.*;
    import java.time.Instant;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    @Builder
    @Table(name = "token")
    @Entity
    public class AccountVerificationToken {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        private String token;
        @OneToOne(fetch = FetchType.LAZY)
        private User user;
        private Instant expirationDate;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;NotificationEmail: subject, recepient, body
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.model;

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class NotificationEmail {
        private String subject;
        private String recepient;
        private String body;
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 2: Creating Repositories 👩‍
&lt;/h2&gt;

&lt;p&gt;Now we need to cover the repositories which will be responsible for storing the entites in the database. Inside &lt;strong&gt;com.you-name.backend&lt;/strong&gt; create a new package called &lt;strong&gt;repository&lt;/strong&gt;, and add the following interfaces.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.repository;

    import com.maxicb.backend.model.User;
    import org.springframework.data.repository.CrudRepository;

    import java.util.Optional;

    public interface UserRepository extends CrudRepository&amp;lt;User, Long&amp;gt; {
        Optional&amp;lt;User&amp;gt; findByUsername(String username);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Post Repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.repository;

    import com.maxicb.backend.model.Post;
    import com.maxicb.backend.model.Subreddit;
    import com.maxicb.backend.model.User;
    import org.springframework.data.repository.CrudRepository;

    import java.util.List;

    public interface PostRepository extends CrudRepository&amp;lt;Post, Long&amp;gt; {
        List&amp;lt;Post&amp;gt; findAllBySubreddit(Subreddit subreddit);

        List&amp;lt;Post&amp;gt; findByUser(User user);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Subreddit Repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.repository;

  import com.maxicb.backend.model.Subreddit;
  import org.springframework.data.repository.CrudRepository;

  import java.util.Optional;

  public interface SubredditRepository extends CrudRepository&amp;lt;Subreddit, Long&amp;gt; {
      Optional&amp;lt;Subreddit&amp;gt; findByName(String subredditName);
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Vote Repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.repository;

    import com.maxicb.backend.model.Post;
    import com.maxicb.backend.model.User;
    import com.maxicb.backend.model.Vote;
    import org.springframework.data.repository.CrudRepository;

    import java.util.Optional;

    public interface VoteRepository extends CrudRepository&amp;lt;Vote, Long&amp;gt; {
        Optional&amp;lt;Vote&amp;gt; findTopByPostAndUserOrderByVoteIdDesc(Post post, User currentUser);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Comment Repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    package com.maxicb.backend.repository;

    import com.maxicb.backend.model.Comment;
    import com.maxicb.backend.model.Post;
    import com.maxicb.backend.model.User;
    import org.springframework.data.repository.CrudRepository;

    import java.util.List;

    public interface CommentRepository extends CrudRepository&amp;lt;Comment, Long&amp;gt; {
        List&amp;lt;Comment&amp;gt; findByPost(Post post);

        List&amp;lt;Comment&amp;gt; findAllByUser(User user);
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Token Repository:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  package com.maxicb.backend.repository;

import com.maxicb.backend.model.AccountVerificationToken;
import org.springframework.data.repository.CrudRepository;

import java.util.Optional;

public interface TokenRepository extends CrudRepository&amp;lt;AccountVerificationToken, Long&amp;gt; {
    Optional&amp;lt;AccountVerificationToken&amp;gt; findByToken(String token);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FujCpRgd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FujCpRgd.png" title="Successful Run" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In this article we created the entities, and repositories needed within our Spring Boot backend. Laying the foundation for all of the logic that will follow.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-3-4a4n"&gt;Part 3 &lt;/a&gt; Implementing registration, email sending, and account activation/verification.
&lt;/h2&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 1</title>
      <dc:creator>MaxiCB</dc:creator>
      <pubDate>Sat, 25 Jul 2020 21:53:45 +0000</pubDate>
      <link>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-1-1c22</link>
      <guid>https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-1-1c22</guid>
      <description>&lt;h1&gt;
  
  
  Full Stack Reddit Clone - Spring Boot, React, Electron App - Part 1
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this series of blog posts, we will be building a Reddit clone with Spring Boot, React, and Electron. We will be using varying Spring Technologies like Spring Data JPA, Spring Security with JWT, and PostgreSQL for the database with Redis for Caching. The frontend portion will be using React with Typescript, Redux for state management, and Material-UI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Backend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/backend" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/backend&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Frontend Source: &lt;a href="https://github.com/MaxiCB/vox-nobis/tree/master/client" rel="noopener noreferrer"&gt;https://github.com/MaxiCB/vox-nobis/tree/master/client&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Trello Board: &lt;a href="https://trello.com/b/Aw4GcVFv" rel="noopener noreferrer"&gt;https://trello.com/b/Aw4GcVFv&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Live URL: In Progress&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Backend Project Initialization 👩‍💻
&lt;/h2&gt;

&lt;p&gt;Let's get started building the backend of this application, the first thing we will do is initialize the project using the &lt;a href="https://start.spring.io/" rel="noopener noreferrer"&gt;Spring Initializer Website&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Configure the project as follows&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project: Maven Project&lt;/li&gt;
&lt;li&gt;Language: Java&lt;/li&gt;
&lt;li&gt;Spring Boot: 2.3.2&lt;/li&gt;
&lt;li&gt;Project Metadata:&lt;/li&gt;
&lt;li&gt;Group: com.your-name-here&lt;/li&gt;
&lt;li&gt;Artifact: backend&lt;/li&gt;
&lt;li&gt;Packaging: JAR&lt;/li&gt;
&lt;li&gt;Java: 11&lt;/li&gt;
&lt;li&gt;Dependencies:&lt;/li&gt;
&lt;li&gt;Lombok&lt;/li&gt;
&lt;li&gt;Spring Web&lt;/li&gt;
&lt;li&gt;Spring Security&lt;/li&gt;
&lt;li&gt;Spring Data JPA&lt;/li&gt;
&lt;li&gt;Java Mail Sender&lt;/li&gt;
&lt;li&gt;Thymeleaf&lt;/li&gt;
&lt;li&gt;PostgreSQL Driver&lt;/li&gt;
&lt;li&gt;Spring Data Redis (Access+Driver)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Click generate project, download the project, and extract the contents somewhere safe.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;Open the project in your favorite IDE, and ensure the project structure looks similar to below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FNvOcnmN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FNvOcnmN.png" title="Project Structure" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 2: Additional Dependencies 📚
&lt;/h2&gt;

&lt;p&gt;Now we need to add a couple additional dependencies that were not available in the project initializer&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Open the pom.xml file and add the following dependencies for JWT Authentication, TimeAgo, Validator, and JavaFaker for future testing.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!-- JavaFaker related dependencies--&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.github.javafaker&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;javafaker&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.12&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;!-- JWT related dependencies--&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;io.jsonwebtoken&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jjwt-api&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;0.11.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
&amp;lt;groupId&amp;gt;org.springframework.boot&amp;lt;/groupId&amp;gt;
&amp;lt;artifactId&amp;gt;spring-boot-starter-validation&amp;lt;/artifactId&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;io.jsonwebtoken&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jjwt-impl&amp;lt;/artifactId&amp;gt;
    &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
    &amp;lt;version&amp;gt;0.11.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;io.jsonwebtoken&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;jjwt-jackson&amp;lt;/artifactId&amp;gt;
    &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
    &amp;lt;version&amp;gt;0.11.2&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;!-- TimeAgo related dependencies--&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;com.github.marlonlom&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;timeago&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;4.0.1&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.jetbrains.kotlin&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kotlin-stdlib-jdk8&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${kotlin.version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;
&amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;org.jetbrains.kotlin&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;kotlin-test&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${kotlin.version}&amp;lt;/version&amp;gt;
    &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
&amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 3: Database, Hibernate, and Java Mail Configuration ⚙
&lt;/h2&gt;

&lt;p&gt;Now we need to configure PostgreSQL, Hibernate JPA, Java Mail, and Redis&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I am assuming you already have PostgreSQL, and Redis installed and setup.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.postgresql.org/download/" rel="noopener noreferrer"&gt;PostgreSQL Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://redis.io/download" rel="noopener noreferrer"&gt;Redis Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;You will also need to create an account at &lt;a href="https://mailtrap.io/" rel="noopener noreferrer"&gt;Mailtrap&lt;/a&gt;, to send account verification and notification emails. The reason this is needed is to have access to a fake SMTP Server through MailTrap. You can access the connections details by logging in, and selecting the cog icon on the demo inbox.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open the &lt;strong&gt;src/main/resources/application.properties&lt;/strong&gt; file and add the following&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Database Properties
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=&amp;lt;your-db-username&amp;gt;
spring.datasource.password=&amp;lt;your-db-password&amp;gt;
spring.datasource.initialization-mode=always
spring.jpa.hibernate.ddl-auto=create-drop
spring.jpa.show-sql=true
spring.jpa.generate-ddl=true
# Redis Properties
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379
# Mail Properties
spring.mail.host=smtp.mailtrap.io
spring.mail.port=25
spring.mail.username=&amp;lt;your-smtp-username&amp;gt;
spring.mail.password=&amp;lt;your-smtp-password&amp;gt;
spring.mail.protocol=smtp
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion 🔍
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;To ensure everything is configured correctly you can run the application, and ensure there are no error in the console. Towards the bottom of the console you should see output similar to below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FujCpRgd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgur.com%2FujCpRgd.png" title="Successful Run" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In this article we covered the initialization of our Spring Boot backend.  &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Added JWT, TimeAgo, and JavaFaker dependencies for user authentication, displaying dates as relative time ago language, and generating fake data for future testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Added all the needed configuration for our backend to connect to our database, redis, and mail trap.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next 📺
&lt;/h2&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://dev.to/maxicb/full-stack-reddit-clone-spring-boot-react-electron-app-part-2-446l"&gt;Part 2 &lt;/a&gt; Creating all of the domain entities, and repositories needed within the backend.
&lt;/h2&gt;

</description>
      <category>react</category>
      <category>java</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
