Skip to content

Spring MVC practice #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ private ClientUtil() {
*/
@SneakyThrows
public static Socket openSocket(String host, int port) {
throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ClientUtilTest
return new Socket(host, port);
}

/**
Expand Down Expand Up @@ -62,6 +62,8 @@ public static String readMessage(BufferedReader reader) {
*/
@SneakyThrows
public static void writeToSocket(String message, Socket socket) {
throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ClientUtilTest
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write(message);
writer.flush();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static String getLocalHost() {
*/
@SneakyThrows
public static ServerSocket createServerSocket(int port) {
throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ServerUtilTest
return new ServerSocket(port);
}

/**
Expand All @@ -52,7 +52,7 @@ public static ServerSocket createServerSocket(int port) {
*/
@SneakyThrows
public static Socket acceptClientSocket(ServerSocket serverSocket) {
throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ServerUtilTest
return serverSocket.accept();
}

/**
Expand All @@ -66,7 +66,8 @@ public static Socket acceptClientSocket(ServerSocket serverSocket) {
*/
@SneakyThrows
public static String readMessageFromSocket(Socket socket) {
throw new ExerciseNotCompletedException(); // todo: implement according to javadoc and verify by ServerUtilTest
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
return bufferedReader.readLine();
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.bobocode.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.time.LocalDate;

@WebServlet("/date")
public class DateServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
var writer = resp.getWriter();
var date = LocalDate.now();
writer.println(date);
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,40 @@
package com.bobocode.config;

import com.bobocode.TestDataGenerator;
import com.bobocode.dao.AccountDao;
import com.bobocode.dao.FakeAccountDao;
import com.bobocode.model.Account;
import com.bobocode.service.AccountService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import java.util.List;

/**
* This class specifies application context configuration. It tells Spring to scan "dao" and "service" packages in order
* to find and create instances for {@link com.bobocode.dao.FakeAccountDao} and
* {@link com.bobocode.service.AccountService}.
* to find and create instances for {@link FakeAccountDao} and
* {@link AccountService}.
* <p>
* It also explicitly configures a bean of {@link TestDataGenerator} called "dataGenerator". This beans will be injected
* into {@link com.bobocode.dao.FakeAccountDao} in order to generate some fake accounts.
* into {@link FakeAccountDao} in order to generate some fake accounts.
*/
@Configuration
@ComponentScan(basePackages = {"com.bobocode.dao", "com.bobocode.service"})
public class ApplicationConfig {
// todo: configure application context according to javadoc by following tests in ApplicationConfigTest
// todo: verify final implementation by running ApplicationContextTest
@Bean
public TestDataGenerator dataGenerator() {
return new TestDataGenerator();
}

@Bean
public AccountDao accountDao() {
return new FakeAccountDao(dataGenerator());
}

@Bean
public AccountService accountService() {
return new AccountService(accountDao());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.bobocode.TestDataGenerator;
import com.bobocode.model.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Stream;
Expand All @@ -16,9 +18,11 @@
* Its bean is called "accountDao". And it uses constructor with explicit autowired annotation in order to inject
* {@link TestDataGenerator} instance.
*/
@Component("accountDao")
public class FakeAccountDao implements AccountDao {
private List<Account> accounts;

@Autowired
public FakeAccountDao(TestDataGenerator testDataGenerator) {
this.accounts = Stream.generate(testDataGenerator::generateAccount)
.limit(20)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import com.bobocode.dao.AccountDao;
import com.bobocode.model.Account;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import static java.util.Comparator.comparing;

Expand All @@ -12,6 +14,7 @@
* Since it's a service that should be added to the application context, it is marked as Spring service. It order to get
* {@link AccountDao} instances, it uses implicit constructor-based injection.
*/
@Service
public class AccountService {
private final AccountDao accountDao;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ static class TestConfig {
@DisplayName("DataGenerator has only one bean")
void dataGeneratorHasOnlyOneBean() {
Map<String, TestDataGenerator> testDataGeneratorMap = applicationContext.getBeansOfType(TestDataGenerator.class);

assertThat(testDataGeneratorMap.size()).isEqualTo(1);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package com.bobocode.mvc.api;

import com.bobocode.mvc.data.Notes;
import com.bobocode.mvc.model.Note;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
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;

import java.util.List;

/**
* This controller provides a very simple REST API for Notes. It implements two endpoints that allow you to add
Expand All @@ -19,8 +27,21 @@
* via models, like in {@link com.bobocode.mvc.controller.NoteController}
*/
@RequiredArgsConstructor
@RestController
@RequestMapping("/api/notes")
public class NoteRestController {
private final Notes notes;

// TODO: implement controller methods according to the javadoc verify your impl using NoteRestControllerTest
@GetMapping()
public List<Note> getNote() {
return notes.getAll();
}

@PostMapping
public void addNote(@RequestBody Note note) {
if(note.getId() == null) {

}
notes.add(note);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

GET http://localhost:8080/api/notes
###

POST http://localhost:8080/api/notes
Content-Type: application/json

{
"title": "New Note",
"text": "This is a new note."
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
package com.bobocode.mvc.controller;

import com.bobocode.mvc.data.Notes;
import com.bobocode.mvc.model.Note;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.Banner;
import org.springframework.stereotype.Controller;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.ui.Model;

/**
* {@link NoteController} is a typical controller that powers Spring MVC Notes application. This application provides
Expand All @@ -10,7 +18,7 @@
* is already provided as a field of class {@link Notes}. The base URL is `/notes`.
* <p>
* This controller handles the HTTP GET request that should list all notes. In order to do that, it fetches the list
* of notes, adds that list as an attribute to the {@link org.springframework.ui.Model}, and returns a corresponding view.
* of notes, adds that list as an attribute to the {@link Model}, and returns a corresponding view.
* The view (which is Thymeleaf HTML template) expects to receive an attribute called `noteList`.
* In classical Spring MVC, controller methods return a string value which stores a view name.
* A {@link org.springframework.web.servlet.ViewResolver} is already configured to look for an HTML template in
Expand All @@ -27,9 +35,22 @@
* the same controller will look like {@link com.bobocode.mvc.api.NoteRestController}
*/
@RequiredArgsConstructor
@Controller
@RequestMapping("/notes")
public class NoteController {
private final Notes notes;

// TODO: implement controller methods according to the javadoc and verify your impl using NoteControllerTest

@GetMapping()
public String getNotes(Model model){
model.addAttribute("noteList", notes.getAll());
return "notes";
}

@PostMapping
public String addNote(Note note){
notes.add(note);
return "redirect:/notes";
}

}
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.bobocode.config;

import net.bytebuddy.implementation.bind.annotation.IgnoreForBinding;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

Expand All @@ -15,5 +17,18 @@
* todo: enable component scanning for all packages in "com.bobocode"
* todo: ignore all web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc}) using exclude filter
*/
@Configuration
@ComponentScan(basePackages = "com.bobocode",
excludeFilters = {
@Filter(
type = FilterType.ANNOTATION,
classes = EnableWebMvc.class
),
@Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
})
public class RootConfig {

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.bobocode.config;

import com.bobocode.util.ExerciseNotCompletedException;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

/**
Expand All @@ -9,16 +8,16 @@
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
throw new ExerciseNotCompletedException(); //todo: use {@link RootConfig} as root application config class
return new Class<?>[]{RootConfig.class};
}

@Override
protected Class<?>[] getServletConfigClasses() {
throw new ExerciseNotCompletedException(); //todo: use {@link WebConfig} as ServletConfig class
return new Class<?>[]{WebConfig.class};
}

@Override
protected String[] getServletMappings() {
throw new ExerciseNotCompletedException(); //todo: provide default servlet mapping ("/")
return new String[]{"/"};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,8 @@
* todo: enable component scanning for package "web"
*/

@Configuration
@ComponentScan(basePackages = "com.bobocode.web")
@EnableWebMvc
public class WebConfig {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.bobocode.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
* Welcome controller that consists of one method that handles get request to "/welcome" and respond with a message.
* <p>
Expand All @@ -8,8 +12,11 @@
* todo: tell Spring that {@link WelcomeController#welcome()} method provides response body without view
*/

@Controller
public class WelcomeController {

@GetMapping("/welcome")
@ResponseBody
public String welcome() {
return "Welcome to Spring MVC!";
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -170,6 +172,6 @@ void welcomeControllerMethodIsMarkedAsResponseBody() throws NoSuchMethodExceptio
}

private List<Class> getFilteredClasses(Filter[] filters) {
return Stream.of(filters).flatMap(filter -> Stream.of(filter.value())).collect(Collectors.toList());
return Stream.of(filters).flatMap(filter -> Stream.of(filter.classes())).collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.bobocode.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;

Expand All @@ -10,5 +13,17 @@
* todo: 2. Enable component scanning for all packages in "com.bobocode" using annotation property "basePackages"
* todo: 3. Exclude web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc})
*/
@Configuration
@ComponentScan(basePackages = "com.bobocode",
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
),
@ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = EnableWebMvc.class
)
})
public class RootConfig {
}
Loading