diff --git a/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java b/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java index 3b0ce87..c50ab59 100644 --- a/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java +++ b/account-jsp/src/main/java/com/bobocode/config/AccountWebAppInitializer.java @@ -12,16 +12,17 @@ public class AccountWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class>[] getRootConfigClasses() { - throw new UnsupportedOperationException("It's your job to implement this method!"); + return new Class[]{RootConfig.class}; } @Override protected Class>[] getServletConfigClasses() { - throw new UnsupportedOperationException("It's your job to implement this method!"); + return new Class[]{WebConfig.class}; } @Override protected String[] getServletMappings() { - throw new UnsupportedOperationException("It's your job to implement this method!"); + return new String[]{"/"}; } } + diff --git a/account-jsp/src/main/java/com/bobocode/config/RootConfig.java b/account-jsp/src/main/java/com/bobocode/config/RootConfig.java index 27e98f6..043ea11 100644 --- a/account-jsp/src/main/java/com/bobocode/config/RootConfig.java +++ b/account-jsp/src/main/java/com/bobocode/config/RootConfig.java @@ -1,6 +1,10 @@ package com.bobocode.config; import com.bobocode.TestDataGenerator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Controller; import org.springframework.web.servlet.config.annotation.EnableWebMvc; @@ -12,5 +16,12 @@ * todo: 3. Exclude web related config and beans (ignore @{@link Controller}, ignore {@link EnableWebMvc}) * todo: 4. Configure {@link TestDataGenerator} bean with name "dataGenerator" (don't specify name explicitly) */ +@Configuration +@ComponentScan(basePackages = "com.bobocode", excludeFilters = {@Filter(EnableWebMvc.class), @Filter(Controller.class)}) public class RootConfig { + @Bean + public TestDataGenerator dataGenerator() { + return new TestDataGenerator(); + } } + diff --git a/account-jsp/src/main/java/com/bobocode/config/WebConfig.java b/account-jsp/src/main/java/com/bobocode/config/WebConfig.java index edf8c8a..d40a7cc 100644 --- a/account-jsp/src/main/java/com/bobocode/config/WebConfig.java +++ b/account-jsp/src/main/java/com/bobocode/config/WebConfig.java @@ -1,5 +1,12 @@ package com.bobocode.config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.view.InternalResourceViewResolver; + /** * This class provides web (servlet) related configuration. *
@@ -8,6 +15,17 @@
* todo: 3. Enable component scanning for package "web" using annotation value
* todo: 4. Configure JPS internal view resolver with prefix = "/WEB-INF/views/" and suffix ".jsp"
*/
+@Configuration
+@ComponentScan("com.bobocode.web")
+@EnableWebMvc
public class WebConfig {
+ @Bean
+ public ViewResolver viewResolver() {
+ InternalResourceViewResolver resolver = new InternalResourceViewResolver();
+ resolver.setPrefix("/WEB-INF/views/");
+ resolver.setSuffix(".jsp");
+ return resolver;
+ }
}
+
diff --git a/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java b/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java
index f512655..4e9db47 100644
--- a/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java
+++ b/account-jsp/src/main/java/com/bobocode/web/controller/AccountController.java
@@ -2,6 +2,17 @@
import com.bobocode.TestDataGenerator;
import com.bobocode.model.Account;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.Model;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import java.util.List;
+import java.util.stream.Stream;
+
+import static java.util.stream.Collectors.toList;
/**
* This controller provides endpoint that generates a list of {@link Account} and passes it to the view.
@@ -13,6 +24,17 @@
* todo: 5. Provide a default value "10" for parameter "size"
* todo: 6. Pass the list of accounts to the view using model attribute with name "accountList"
*/
+@Controller
+@RequestMapping("/accounts")
public class AccountController {
+ @Autowired
+ private TestDataGenerator dataGenerator;
+ @GetMapping
+ public String getAccounts(@RequestParam(name = "size", defaultValue = "10") int size, Model model) {
+ List
@@ -7,6 +10,13 @@
* todo: 2. Configure HTTP GET mapping "/" and "/welcome" for method {@link WelcomeController#welcome()}
* todo: 3. Forward the request to "welcome.jsp" view
*/
+@Controller
public class WelcomeController {
+ @GetMapping({"/", "/welcome"})
+ public String welcome() {
+ return "welcome";
+ }
+
}
+
diff --git a/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java b/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java
index c5d1a6d..fe8f56e 100644
--- a/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java
+++ b/account-rest-api/src/main/java/com/bobocode/config/RootConfig.java
@@ -1,5 +1,9 @@
package com.bobocode.config;
+import com.bobocode.TestDataGenerator;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.ComponentScan.Filter;
+import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@@ -10,5 +14,8 @@
* 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 = {@Filter(EnableWebMvc.class), @Filter(Controller.class)})
public class RootConfig {
}
+
diff --git a/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java b/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java
index 6284d6a..2b1b98c 100644
--- a/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java
+++ b/account-rest-api/src/main/java/com/bobocode/config/WebConfig.java
@@ -1,5 +1,10 @@
package com.bobocode.config;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
/**
* This class provides web (servlet) related configuration.
*
@@ -7,6 +12,10 @@
* todo: 2. Enable web mvc using annotation
* todo: 3. Enable component scanning for package "web" using annotation value
*/
+@EnableWebMvc
+@Configuration
+@ComponentScan("com.bobocode.web")
public class WebConfig {
}
+
diff --git a/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java b/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java
index af5f026..0401391 100644
--- a/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java
+++ b/account-rest-api/src/main/java/com/bobocode/dao/impl/InMemoryAccountDao.java
@@ -3,6 +3,7 @@
import com.bobocode.dao.AccountDao;
import com.bobocode.exception.EntityNotFountException;
import com.bobocode.model.Account;
+import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
@@ -14,6 +15,7 @@
*
* todo: 1. Configure a component with name "accountDao"
*/
+@Component("accountDao")
public class InMemoryAccountDao implements AccountDao {
private Map
@@ -16,6 +22,46 @@
* todo: 7. Implement method that handles DELETE request with id as path variable removes an account by id
* todo: Configure HTTP response status code 204 - NO CONTENT
*/
+@RestController
+@RequestMapping("/accounts")
public class AccountRestController {
+ private final AccountDao accountDao;
+
+ public AccountRestController(AccountDao accountDao) {
+ this.accountDao = accountDao;
+ }
+
+ @GetMapping
+ public List
@@ -7,5 +11,8 @@
* todo: enable web mvc using annotation
* todo: enable component scanning for package "web"
*/
+@Configuration
+@EnableWebMvc
+@ComponentScan(basePackages = "com.bobocode.web")
public class WebConfig {
}
diff --git a/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java b/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java
index ca389bc..c1209c1 100644
--- a/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java
+++ b/hello-spring-mvc/src/main/java/com/bobocode/web/controller/WelcomeController.java
@@ -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.
*
@@ -7,8 +11,11 @@
* todo: configure HTTP GET mapping "/welcome" for method {@link WelcomeController#welcome()}
* todo: tell Spring that {@link WelcomeController#welcome()} method provides response body
*/
+@Controller
public class WelcomeController {
+ @ResponseBody
+ @GetMapping("/welcome")
public String welcome() {
return "Welcome to Spring MVC!";
}
diff --git a/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java b/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java
index 40419b3..6d6bfca 100644
--- a/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java
+++ b/inter-bean-dependencies/src/main/java/com/bobocode/config/RootConfig.java
@@ -5,26 +5,32 @@
import com.bobocode.dao.impl.FakeAccountDao;
import com.bobocode.service.AccountService;
import org.springframework.context.annotation.Bean;
-import org.springframework.stereotype.Component;
+import org.springframework.context.annotation.Configuration;
/**
* todo: Refactor {@link RootConfig} in order to user inter-bean dependencies properly.
*/
-@Component
-public final class RootConfig {
+@Configuration // @Configuration works a bit differently then @Component
+// In this case Spring uses CGLIB to create a proxy in order to support inter-bean dependencies.
+// It's when you call other method in your config class and still get the same bean instance
+public class RootConfig { // Because CGLIB proxy is created as a subclass of your @Configuration class, RootConfig cannot be final
@Bean
public AccountService accountService() {
- return new AccountService(fakeAccountDao());
+ return new AccountService(fakeAccountDao()); // Although you call fakeAccountDao() method here, it is not called directly
+ // Spring creates proxy that overrides all these method. It caches created beans so when you call method like
+ // fakeAccountDao() it first checks if such beans was created before.
+ // It allows to support default bean scope SINGLETON.
}
@Bean
- public final AccountDao fakeAccountDao() {
+ public AccountDao fakeAccountDao() {
return new FakeAccountDao(dataGenerator());
}
@Bean
- private TestDataGenerator dataGenerator() {
+ public TestDataGenerator dataGenerator() { // Because Spring overrides methods in a proxy,
+ // bean methods in @Configuration classes cannot be final
return new TestDataGenerator();
}
}
diff --git a/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java b/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java
index 81c079d..dd6f746 100644
--- a/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java
+++ b/transactional-user-service/src/main/java/com/bobocode/config/JpaConfig.java
@@ -1,5 +1,7 @@
package com.bobocode.config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.jpa.JpaVendorAdapter;
@@ -20,13 +22,16 @@
* todo: 4. Configure bean {@link javax.persistence.EntityManagerFactory} with name "entityManagerFactory"
*
*/
+@Configuration
public class JpaConfig {
+ @Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
+ @Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabase(Database.H2);
@@ -35,11 +40,12 @@ public JpaVendorAdapter jpaVendorAdapter() {
return adapter;
}
+ @Bean("entityManagerFactory")
public LocalContainerEntityManagerFactoryBean localContainerEMF(DataSource dataSource, JpaVendorAdapter jpaVendorAdapter) {
LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
emf.setDataSource(dataSource);
emf.setJpaVendorAdapter(jpaVendorAdapter);
- // todo: 5. Configure package "com.bobocode.model" to scan for JPA entities
+ emf.setPackagesToScan("com.bobocode.model");
return emf;
}
}
diff --git a/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java b/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java
index 58d3031..3828e95 100644
--- a/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java
+++ b/transactional-user-service/src/main/java/com/bobocode/config/RootConfig.java
@@ -1,6 +1,13 @@
package com.bobocode.config;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import javax.persistence.EntityManagerFactory;
/**
* This class provides root application configuration. It scans for all available beans and enables declarative
@@ -11,6 +18,14 @@
* todo: 3. Configure JPA {@link PlatformTransactionManager} with bean name "transactionManager"
* todo: 4. Enable declarative transaction management
*/
+@Configuration
+@ComponentScan("com.bobocode")
+@EnableTransactionManagement
public class RootConfig {
+ @Bean
+ public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
+ return new JpaTransactionManager(entityManagerFactory);
+ }
}
+
diff --git a/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java b/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java
index 050b2c7..a66d688 100644
--- a/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java
+++ b/transactional-user-service/src/main/java/com/bobocode/dao/impl/JpaUserDao.java
@@ -16,7 +16,10 @@
* todo: 2. Enable transaction management on class level
* todo: 3. Inject {@link EntityManager} using @{@link PersistenceContext} annotation
*/
+@Transactional
+@Repository("userDao")
public class JpaUserDao implements UserDao {
+ @PersistenceContext
private EntityManager entityManager;
@Override
@@ -34,3 +37,4 @@ public void save(User user) {
entityManager.persist(user);
}
}
+
diff --git a/transactional-user-service/src/main/java/com/bobocode/service/UserService.java b/transactional-user-service/src/main/java/com/bobocode/service/UserService.java
index ddbd598..1e5ed49 100644
--- a/transactional-user-service/src/main/java/com/bobocode/service/UserService.java
+++ b/transactional-user-service/src/main/java/com/bobocode/service/UserService.java
@@ -4,7 +4,10 @@
import com.bobocode.model.jpa.Role;
import com.bobocode.model.jpa.RoleType;
import com.bobocode.model.jpa.User;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import java.math.BigDecimal;
import java.util.List;
import static java.util.stream.Collectors.toList;
@@ -18,19 +21,31 @@
* todo: 4. Configure {@link UserService#getAll()} as read-only method
* todo: 4. Configure {@link UserService#getAllAdmins()} as read-only method
*/
+@Service
+@Transactional
public class UserService {
private UserDao userDao;
+ public UserService(UserDao userDao) {
+ this.userDao = userDao;
+ }
+
public void save(User user) {
userDao.save(user);
}
+ @Transactional(readOnly = true)
public List