├── .gitignore ├── Procfile ├── README.md ├── curls.txt ├── pom.xml └── src ├── main ├── java │ └── br │ │ └── com │ │ └── casadocodigo │ │ └── loja │ │ ├── cache │ │ ├── RequestHeaderKey.java │ │ └── RequestHeaderKeyGeneration.java │ │ ├── conf │ │ ├── AmazonConfiguration.java │ │ ├── AppWebConfiguration.java │ │ ├── JPAConfiguration.java │ │ ├── JPAProductionConfiguration.java │ │ ├── SecurityConfiguration.java │ │ ├── ServletSpringMVC.java │ │ └── SpringSecurityFilterConfiguration.java │ │ ├── controllers │ │ ├── AuthController.java │ │ ├── HomeController.java │ │ ├── PaymentController.java │ │ ├── ProductsController.java │ │ ├── ShoppingCartController.java │ │ └── integration │ │ │ ├── PaymentGateway.java │ │ │ └── ProductsRestController.java │ │ ├── converters │ │ └── StringToCalendarConverver.java │ │ ├── daos │ │ ├── ProductDAO.java │ │ └── UserDAO.java │ │ ├── infra │ │ ├── FileSaver.java │ │ ├── HttpPartUtils.java │ │ └── spring │ │ │ └── SetAttributeScopeProcessor.java │ │ ├── models │ │ ├── BookType.java │ │ ├── PaymentData.java │ │ ├── PaymentReturn.java │ │ ├── Price.java │ │ ├── Product.java │ │ ├── Role.java │ │ ├── ShoppingCart.java │ │ ├── ShoppingItem.java │ │ └── SystemUser.java │ │ ├── tags │ │ └── GenericInput.java │ │ ├── validacao │ │ └── ProductValidator.java │ │ └── viewresolver │ │ ├── CustomXMLViewResolver.java │ │ └── JsonViewResolver.java ├── resources │ └── log4j.xml └── webapp │ ├── WEB-INF │ ├── 403.jsp │ ├── custom-form.tld │ ├── footer.jsp │ ├── header.jsp │ ├── messages.properties │ ├── messages_en_US.properties │ ├── messages_pt.properties │ ├── tags │ │ └── page.tag │ ├── views │ │ ├── auth │ │ │ └── login.jsp │ │ ├── hello-world.jsp │ │ ├── products │ │ │ ├── form.jsp │ │ │ ├── list.jsp │ │ │ └── show.jsp │ │ └── shoppingCart │ │ │ └── items.jsp │ └── web.xml │ └── resources │ └── js │ └── jquery.js └── test └── java └── br └── com └── casadocodigo └── loja ├── builders └── ProductBuilder.java ├── conf └── DataSourceConfigurationTest.java ├── controllers └── ProductsControllerTest.java ├── daos └── ProductDAOTest.java └── infra └── FileSaverTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.DS_Store 2 | bin 3 | target 4 | .classpath 5 | .project 6 | .settings 7 | src/main/webapp/META-INF 8 | .idea 9 | *.iml 10 | imagens-textos-livro 11 | jsonData.txt 12 | output.txt 13 | inserts-security.txt 14 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: java $JAVA_OPTS -jar -Dspring.profiles.active=prod target/dependency/webapp-runner.jar --port $PORT target/*.war -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Agradecimento 2 | Obrigado por ter comprado o livro ou por estar interessado no projeto criado a partir do conteúdo do mesmo :). Fique a vontade 3 | para navegar, realizar o download e fazer as experimentações que achar necessárias. 4 | 5 | ##Informações importantes sobre o projeto 6 | 7 | * Caso precise, faça o download do zip do projeto pronto, basta seguir este link -> https://github.com/livrospringmvc/lojacasadocodigo/archive/versao_download.zip 8 | * O projeto pronto para download, aponta para um banco mysql chamado "casadocodigo", fique atento a isso. 9 | * A maioria dos commits foram feitos pensando nos capítulos do livro, então fique a vontade para clonar o projeto e navegar entre eles. 10 | -------------------------------------------------------------------------------- /curls.txt: -------------------------------------------------------------------------------- 1 | curl -H "Accept:application/json" -X GET "http://localhost:8080/casadocodigo/produtos" 2 | curl -H "Accept:text/html" -X GET "http://localhost:8080/casadocodigo/produtos" -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | br.com.caelum 5 | casadocodigo 6 | 0.0.1-SNAPSHOT 7 | war 8 | Casa do codigo 9 | 10 | 11 | 1.8 12 | 4.1.0.RELEASE 13 | 4.0.0.M2 14 | 1.6.1 15 | 16 | 17 | 18 | 19 | org.springframework 20 | spring-webmvc 21 | ${org.springframework-version} 22 | 23 | 24 | 25 | 26 | org.apache.tomcat 27 | tomcat-servlet-api 28 | 7.0.30 29 | provided 30 | 31 | 32 | javax.servlet.jsp 33 | jsp-api 34 | 2.1 35 | provided 36 | 37 | 38 | javax.servlet.jsp.jstl 39 | jstl-api 40 | 1.2 41 | 42 | 43 | javax.servlet 44 | servlet-api 45 | 46 | 47 | 48 | 49 | org.glassfish.web 50 | jstl-impl 51 | 1.2 52 | 53 | 54 | javax.servlet 55 | servlet-api 56 | 57 | 58 | 59 | 60 | 61 | org.slf4j 62 | slf4j-api 63 | ${org.slf4j-version} 64 | 65 | 66 | org.slf4j 67 | jcl-over-slf4j 68 | ${org.slf4j-version} 69 | 70 | 71 | 72 | org.slf4j 73 | slf4j-log4j12 74 | ${org.slf4j-version} 75 | 76 | 77 | 78 | log4j 79 | log4j 80 | 1.2.16 81 | 82 | 83 | 84 | 85 | org.hibernate 86 | hibernate-entitymanager 87 | 4.3.0.Final 88 | 89 | 90 | 91 | org.hibernate 92 | hibernate-core 93 | 4.3.0.Final 94 | 95 | 96 | 97 | org.hibernate.javax.persistence 98 | hibernate-jpa-2.1-api 99 | 1.0.0.Final 100 | 101 | 102 | 103 | org.springframework 104 | spring-orm 105 | ${org.springframework-version} 106 | 107 | 108 | 109 | 110 | mysql 111 | mysql-connector-java 112 | 5.1.15 113 | 114 | 115 | 116 | 117 | javax.validation 118 | validation-api 119 | 1.0.0.GA 120 | 121 | 122 | org.hibernate 123 | hibernate-validator 124 | 4.1.0.Final 125 | 126 | 127 | 128 | 129 | 130 | commons-io 131 | commons-io 132 | 2.4 133 | 134 | 135 | 136 | 137 | 138 | javax.inject 139 | javax.inject 140 | 1 141 | 142 | 143 | 144 | 145 | 146 | 147 | com.fasterxml.jackson.core 148 | jackson-core 149 | 2.5.1 150 | 151 | 152 | 153 | com.fasterxml.jackson.core 154 | jackson-databind 155 | 2.5.1 156 | 157 | 158 | 159 | 160 | 161 | com.google.guava 162 | guava 163 | 18.0 164 | 165 | 166 | 167 | org.springframework 168 | spring-context-support 169 | ${org.springframework-version} 170 | 171 | 172 | 173 | 174 | 175 | org.springframework 176 | spring-oxm 177 | ${org.springframework-version} 178 | 179 | 180 | 181 | com.thoughtworks.xstream 182 | xstream 183 | 1.4.8 184 | 185 | 186 | 187 | 188 | 189 | org.springframework.security 190 | spring-security-config 191 | ${org.springframework.security-version} 192 | 193 | 194 | org.springframework.security 195 | spring-security-taglibs 196 | ${org.springframework.security-version} 197 | 198 | 199 | org.springframework.security 200 | spring-security-web 201 | ${org.springframework.security-version} 202 | 203 | 204 | org.springframework.security 205 | spring-security-core 206 | ${org.springframework.security-version} 207 | 208 | 209 | 210 | 211 | junit 212 | junit 213 | 4.12 214 | test 215 | 216 | 217 | 218 | org.springframework 219 | spring-test 220 | ${org.springframework-version} 221 | 222 | 223 | 224 | org.springframework.security 225 | spring-security-test 226 | ${org.springframework.security-version} 227 | 228 | 229 | 230 | 231 | 232 | javax.mail 233 | mail 234 | 1.4.7 235 | 236 | 237 | 238 | 239 | 240 | org.postgresql 241 | postgresql 242 | 9.4-1201-jdbc41 243 | 244 | 245 | 246 | 247 | com.scireum 248 | s3ninja 249 | 2.3.2 250 | 251 | 252 | 253 | com.amazonaws 254 | aws-java-sdk 255 | 1.9.11 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | spring-milestones 267 | Spring Milestones 268 | http://repo.spring.io/milestone 269 | 270 | false 271 | 272 | 273 | 274 | 275 | sonatype-oss-public 276 | http://oss.sonatype.org/content/groups/public/ 277 | 278 | true 279 | 280 | 281 | true 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | org.apache.maven.plugins 291 | maven-compiler-plugin 292 | 3.1 293 | 294 | 1.8 295 | 1.8 296 | 297 | 298 | 299 | org.apache.maven.plugins 300 | maven-eclipse-plugin 301 | 2.9 302 | 303 | true 304 | 305 | 3.1 306 | 307 | 308 | 309 | 310 | org.apache.maven.plugins 311 | maven-dependency-plugin 312 | 2.3 313 | 314 | 315 | package 316 | 317 | copy 318 | 319 | 320 | 321 | 322 | com.github.jsimone 323 | webapp-runner 324 | 7.0.57.2 325 | webapp-runner.jar 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/cache/RequestHeaderKey.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.cache; 2 | 3 | public class RequestHeaderKey { 4 | 5 | private String header; 6 | private Object generate; 7 | 8 | public RequestHeaderKey(String header, Object generate) { 9 | this.header = header; 10 | this.generate = generate; 11 | } 12 | 13 | @Override 14 | public int hashCode() { 15 | final int prime = 31; 16 | int result = 1; 17 | result = prime * result 18 | + ((generate == null) ? 0 : generate.hashCode()); 19 | result = prime * result + ((header == null) ? 0 : header.hashCode()); 20 | return result; 21 | } 22 | 23 | @Override 24 | public boolean equals(Object obj) { 25 | if (this == obj) 26 | return true; 27 | if (obj == null) 28 | return false; 29 | if (getClass() != obj.getClass()) 30 | return false; 31 | RequestHeaderKey other = (RequestHeaderKey) obj; 32 | if (generate == null) { 33 | if (other.generate != null) 34 | return false; 35 | } else if (!generate.equals(other.generate)) 36 | return false; 37 | if (header == null) { 38 | if (other.header != null) 39 | return false; 40 | } else if (!header.equals(other.header)) 41 | return false; 42 | return true; 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/cache/RequestHeaderKeyGeneration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.cache; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.cache.interceptor.KeyGenerator; 7 | import org.springframework.cache.interceptor.SimpleKeyGenerator; 8 | import org.springframework.context.annotation.Scope; 9 | import org.springframework.http.HttpHeaders; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.context.WebApplicationContext; 12 | import org.springframework.web.context.request.WebRequest; 13 | 14 | @Component("headerKeyGenerator") 15 | @Scope(value=WebApplicationContext.SCOPE_REQUEST) 16 | public class RequestHeaderKeyGeneration implements KeyGenerator{ 17 | 18 | @Autowired 19 | private WebRequest request; 20 | 21 | @Override 22 | public Object generate(Object target, Method method, Object... params) { 23 | SimpleKeyGenerator simpleKeyGenerator = new SimpleKeyGenerator(); 24 | String header = request.getHeader(HttpHeaders.ACCEPT); 25 | Object delegateKey = simpleKeyGenerator.generate(target, method, params); 26 | return new RequestHeaderKey(header,delegateKey); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/AmazonConfiguration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | 5 | import com.amazonaws.ClientConfiguration; 6 | import com.amazonaws.auth.AWSCredentials; 7 | import com.amazonaws.auth.BasicAWSCredentials; 8 | import com.amazonaws.services.s3.AmazonS3Client; 9 | import com.amazonaws.services.s3.S3ClientOptions; 10 | 11 | public class AmazonConfiguration { 12 | 13 | @Bean 14 | public AmazonS3Client s3Ninja() { 15 | AWSCredentials credentials = new BasicAWSCredentials( 16 | "AKIAIOSFODNN7EXAMPLE", 17 | "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"); 18 | AmazonS3Client newClient = new AmazonS3Client(credentials, 19 | new ClientConfiguration()); 20 | newClient.setS3ClientOptions(new S3ClientOptions() 21 | .withPathStyleAccess(true)); 22 | newClient.setEndpoint("http://localhost:9444/s3"); 23 | return newClient; 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/AppWebConfiguration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | import java.util.Properties; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | import org.springframework.cache.CacheManager; 9 | import org.springframework.cache.annotation.EnableCaching; 10 | import org.springframework.cache.guava.GuavaCacheManager; 11 | import org.springframework.context.MessageSource; 12 | import org.springframework.context.annotation.Bean; 13 | import org.springframework.context.annotation.ComponentScan; 14 | import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; 15 | import org.springframework.context.support.ReloadableResourceBundleMessageSource; 16 | import org.springframework.format.datetime.DateFormatter; 17 | import org.springframework.format.datetime.DateFormatterRegistrar; 18 | import org.springframework.format.support.DefaultFormattingConversionService; 19 | import org.springframework.format.support.FormattingConversionService; 20 | import org.springframework.mail.MailSender; 21 | import org.springframework.mail.javamail.JavaMailSenderImpl; 22 | import org.springframework.oxm.jaxb.Jaxb2Marshaller; 23 | import org.springframework.web.accept.ContentNegotiationManager; 24 | import org.springframework.web.client.RestTemplate; 25 | import org.springframework.web.multipart.MultipartResolver; 26 | import org.springframework.web.multipart.support.StandardServletMultipartResolver; 27 | import org.springframework.web.servlet.LocaleResolver; 28 | import org.springframework.web.servlet.ViewResolver; 29 | import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; 30 | import org.springframework.web.servlet.config.annotation.EnableWebMvc; 31 | import org.springframework.web.servlet.config.annotation.InterceptorRegistry; 32 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 33 | import org.springframework.web.servlet.i18n.CookieLocaleResolver; 34 | import org.springframework.web.servlet.i18n.LocaleChangeInterceptor; 35 | import org.springframework.web.servlet.view.ContentNegotiatingViewResolver; 36 | import org.springframework.web.servlet.view.InternalResourceViewResolver; 37 | 38 | import br.com.casadocodigo.loja.cache.RequestHeaderKeyGeneration; 39 | import br.com.casadocodigo.loja.controllers.HomeController; 40 | import br.com.casadocodigo.loja.daos.ProductDAO; 41 | import br.com.casadocodigo.loja.infra.FileSaver; 42 | import br.com.casadocodigo.loja.models.Product; 43 | import br.com.casadocodigo.loja.models.ShoppingCart; 44 | import br.com.casadocodigo.loja.viewresolver.CustomXMLViewResolver; 45 | import br.com.casadocodigo.loja.viewresolver.JsonViewResolver; 46 | 47 | import com.google.common.cache.CacheBuilder; 48 | 49 | @EnableWebMvc 50 | @ComponentScan(basePackageClasses = { HomeController.class, ProductDAO.class, 51 | FileSaver.class, ShoppingCart.class, RequestHeaderKeyGeneration.class }) 52 | @EnableCaching 53 | public class AppWebConfiguration extends WebMvcConfigurerAdapter{ 54 | 55 | @Override 56 | public void addInterceptors(InterceptorRegistry registry) { 57 | registry.addInterceptor(new LocaleChangeInterceptor()); 58 | } 59 | 60 | @Bean 61 | public LocaleResolver localeResolver(){ 62 | return new CookieLocaleResolver(); 63 | } 64 | 65 | @Override 66 | public void configureDefaultServletHandling( 67 | DefaultServletHandlerConfigurer configurer) { 68 | configurer.enable(); 69 | } 70 | 71 | @Bean 72 | public ViewResolver contentNegotiatingViewResolver( 73 | ContentNegotiationManager manager) { 74 | List resolvers = new ArrayList(); 75 | 76 | resolvers.add(internalResourceViewResolver()); 77 | resolvers.add(new JsonViewResolver()); 78 | resolvers.add(getMarshallingXmlViewResolver()); 79 | 80 | ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver(); 81 | resolver.setViewResolvers(resolvers); 82 | resolver.setContentNegotiationManager(manager); 83 | return resolver; 84 | } 85 | 86 | @Bean 87 | public CustomXMLViewResolver getMarshallingXmlViewResolver() { 88 | Jaxb2Marshaller marshaller = new Jaxb2Marshaller(); 89 | marshaller.setClassesToBeBound(Product.class); 90 | // XStreamMarshaller marshaller = new XStreamMarshaller(); 91 | // HashMap> keys = new HashMap>(); 92 | // keys.put("product", Product.class); 93 | // keys.put("price", Price.class); 94 | // marshaller.setAliases(keys); 95 | return new CustomXMLViewResolver(marshaller); 96 | } 97 | 98 | @Bean 99 | public InternalResourceViewResolver internalResourceViewResolver() { 100 | InternalResourceViewResolver resolver = new InternalResourceViewResolver(); 101 | resolver.setPrefix("/WEB-INF/views/"); 102 | resolver.setSuffix(".jsp"); 103 | resolver.setExposedContextBeanNames("shoppingCart"); 104 | return resolver; 105 | } 106 | 107 | @Bean(name="messageSource") 108 | public MessageSource loadBundle() { 109 | ReloadableResourceBundleMessageSource bundle = new ReloadableResourceBundleMessageSource(); 110 | bundle.setBasename("/WEB-INF/messages"); 111 | bundle.setDefaultEncoding("UTF-8"); 112 | bundle.setCacheSeconds(1); 113 | return bundle; 114 | } 115 | 116 | @Bean 117 | public FormattingConversionService mvcConversionService() { 118 | DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService( 119 | true); 120 | 121 | DateFormatterRegistrar registrar = new DateFormatterRegistrar(); 122 | registrar.setFormatter(new DateFormatter("yyyy-MM-dd")); 123 | registrar.registerFormatters(conversionService); 124 | return conversionService; 125 | } 126 | 127 | @Bean 128 | public RestTemplate restTemplate() { 129 | return new RestTemplate(); 130 | } 131 | 132 | @Bean 133 | public CacheManager cacheManager() { 134 | CacheBuilder builder = CacheBuilder.newBuilder() 135 | .maximumSize(100).expireAfterAccess(5, TimeUnit.MINUTES); 136 | GuavaCacheManager cacheManager = new GuavaCacheManager(); 137 | cacheManager.setCacheBuilder(builder); 138 | return cacheManager; 139 | } 140 | 141 | @Bean 142 | public MultipartResolver multipartResolver() { 143 | return new StandardServletMultipartResolver(); 144 | } 145 | 146 | @Bean 147 | public MailSender mailSender() { 148 | 149 | JavaMailSenderImpl javaMailSenderImpl = new JavaMailSenderImpl(); 150 | javaMailSenderImpl.setHost("smtp.gmail.com"); 151 | javaMailSenderImpl.setPassword("password"); 152 | javaMailSenderImpl.setPort(587); 153 | javaMailSenderImpl.setUsername("compras@casadocodigo.com.br"); 154 | Properties mailProperties = new Properties(); 155 | mailProperties.put("mail.smtp.auth", true); 156 | mailProperties.put("mail.smtp.starttls.enable", true); 157 | javaMailSenderImpl.setJavaMailProperties(mailProperties); 158 | 159 | return javaMailSenderImpl; 160 | } 161 | 162 | } 163 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/JPAConfiguration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import java.util.Properties; 4 | 5 | import javax.persistence.EntityManagerFactory; 6 | import javax.sql.DataSource; 7 | 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Profile; 11 | import org.springframework.core.env.Environment; 12 | import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; 13 | import org.springframework.jdbc.datasource.DriverManagerDataSource; 14 | import org.springframework.orm.jpa.JpaTransactionManager; 15 | import org.springframework.orm.jpa.JpaVendorAdapter; 16 | import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; 17 | import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter; 18 | import org.springframework.transaction.PlatformTransactionManager; 19 | import org.springframework.transaction.annotation.EnableTransactionManagement; 20 | 21 | @Configuration 22 | @EnableTransactionManagement 23 | public class JPAConfiguration { 24 | 25 | 26 | @Bean 27 | public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource) { 28 | LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean(); 29 | em.setDataSource(dataSource); 30 | em.setPackagesToScan(new String[] { "br.com.casadocodigo.loja.models" }); 31 | 32 | JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter(); 33 | em.setJpaVendorAdapter(vendorAdapter); 34 | em.setJpaProperties(additionalProperties()); 35 | 36 | return em; 37 | } 38 | 39 | @Bean 40 | @Profile("dev") 41 | public DataSource dataSource(Environment environment){ 42 | DriverManagerDataSource dataSource = new DriverManagerDataSource(); 43 | dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 44 | dataSource.setUrl("jdbc:mysql://localhost:3306/casadocodigo"); 45 | dataSource.setUsername( "root" ); 46 | dataSource.setPassword( "" ); 47 | return dataSource; 48 | } 49 | 50 | @Bean 51 | public PlatformTransactionManager transactionManager(EntityManagerFactory emf){ 52 | JpaTransactionManager transactionManager = new JpaTransactionManager(); 53 | transactionManager.setEntityManagerFactory(emf); 54 | return transactionManager; 55 | } 56 | 57 | @Bean 58 | public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){ 59 | return new PersistenceExceptionTranslationPostProcessor(); 60 | } 61 | 62 | Properties additionalProperties() { 63 | Properties properties = new Properties(); 64 | properties.setProperty("hibernate.hbm2ddl.auto", "update"); 65 | properties.setProperty("hibernate.show_sql", "true"); 66 | return properties; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/JPAProductionConfiguration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import java.net.URI; 4 | import java.net.URISyntaxException; 5 | 6 | import javax.sql.DataSource; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Profile; 11 | import org.springframework.core.env.Environment; 12 | import org.springframework.jdbc.datasource.DriverManagerDataSource; 13 | 14 | @Profile("prod") 15 | public class JPAProductionConfiguration { 16 | 17 | @Autowired 18 | private Environment environment; 19 | 20 | @Bean 21 | public DataSource dataSource() throws URISyntaxException{ 22 | DriverManagerDataSource dataSource = new DriverManagerDataSource(); 23 | dataSource.setDriverClassName("org.postgresql.Driver"); 24 | URI dbUrl = new URI(environment.getProperty("DATABASE_URL")); 25 | dataSource.setUrl("jdbc:postgresql://" + dbUrl.getHost() + ":" + dbUrl.getPort() + dbUrl.getPath()); 26 | dataSource.setUsername(dbUrl.getUserInfo().split(":")[0]); 27 | dataSource.setPassword(dbUrl.getUserInfo().split(":")[1]); 28 | return dataSource; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/SecurityConfiguration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.http.HttpMethod; 5 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 6 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 7 | import org.springframework.security.config.annotation.web.builders.WebSecurity; 8 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 9 | import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity; 10 | import org.springframework.security.core.userdetails.UserDetailsService; 11 | import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 12 | import org.springframework.security.web.util.matcher.AntPathRequestMatcher; 13 | 14 | @EnableWebMvcSecurity 15 | public class SecurityConfiguration extends WebSecurityConfigurerAdapter{ 16 | 17 | @Override 18 | protected void configure(HttpSecurity http) throws Exception { 19 | http.authorizeRequests() 20 | .antMatchers("/produtos/form").hasRole("ADMIN") 21 | .antMatchers("/shopping/**").permitAll() 22 | .antMatchers(HttpMethod.POST,"/produtos").hasRole("ADMIN") 23 | .antMatchers("/produtos/**").permitAll() 24 | .anyRequest().authenticated() 25 | .and() 26 | .formLogin().loginPage("/login").permitAll() 27 | .and() 28 | .logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")); 29 | } 30 | 31 | @Autowired 32 | private UserDetailsService users; 33 | 34 | @Override 35 | protected void configure(AuthenticationManagerBuilder auth) 36 | throws Exception { 37 | auth.userDetailsService(users).passwordEncoder(new BCryptPasswordEncoder()); 38 | } 39 | 40 | @Override 41 | public void configure(WebSecurity web) throws Exception { 42 | web.ignoring().antMatchers("/resources/**"); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/ServletSpringMVC.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import javax.servlet.Filter; 4 | import javax.servlet.MultipartConfigElement; 5 | import javax.servlet.ServletContext; 6 | import javax.servlet.ServletException; 7 | import javax.servlet.ServletRegistration.Dynamic; 8 | 9 | import org.springframework.core.env.AbstractEnvironment; 10 | import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; 11 | import org.springframework.web.context.request.RequestContextListener; 12 | import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer; 13 | 14 | public class ServletSpringMVC extends 15 | AbstractAnnotationConfigDispatcherServletInitializer { 16 | 17 | @Override 18 | protected Class>[] getRootConfigClasses() { 19 | return new Class[] { SecurityConfiguration.class, 20 | AppWebConfiguration.class, JPAConfiguration.class, 21 | JPAProductionConfiguration.class,AmazonConfiguration.class }; 22 | } 23 | 24 | @Override 25 | protected Class>[] getServletConfigClasses() { 26 | // Tem que colocar aqui para ser adicionado no carregamento da servlet 27 | // base 28 | return new Class[] {}; 29 | } 30 | 31 | @Override 32 | protected String[] getServletMappings() { 33 | // TODO Auto-generated method stub 34 | return new String[] { "/" }; 35 | } 36 | 37 | @Override 38 | protected void customizeRegistration(Dynamic registration) { 39 | super.customizeRegistration(registration); 40 | registration.setMultipartConfig(new MultipartConfigElement("")); 41 | } 42 | 43 | @Override 44 | public void onStartup(ServletContext servletContext) 45 | throws ServletException { 46 | super.onStartup(servletContext); 47 | servletContext.addListener(RequestContextListener.class); 48 | servletContext.setInitParameter( 49 | AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, "dev"); 50 | 51 | } 52 | 53 | @Override 54 | protected Filter[] getServletFilters() { 55 | return new Filter[] { new OpenEntityManagerInViewFilter() }; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/conf/SpringSecurityFilterConfiguration.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer; 4 | 5 | public class SpringSecurityFilterConfiguration extends AbstractSecurityWebApplicationInitializer{ 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/AuthController.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class AuthController { 8 | 9 | @RequestMapping("/login") 10 | public String loginPage(){ 11 | return "auth/login"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/HomeController.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class HomeController { 8 | 9 | @RequestMapping("/") 10 | public String index(){ 11 | return "hello-world"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/PaymentController.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.concurrent.Callable; 5 | 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.mail.MailSender; 8 | import org.springframework.mail.SimpleMailMessage; 9 | import org.springframework.security.core.Authentication; 10 | import org.springframework.security.core.context.SecurityContext; 11 | import org.springframework.security.core.context.SecurityContextHolder; 12 | import org.springframework.security.web.bind.annotation.AuthenticationPrincipal; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestMethod; 15 | import org.springframework.web.bind.annotation.RestController; 16 | import org.springframework.web.client.HttpClientErrorException; 17 | import org.springframework.web.client.RestTemplate; 18 | import org.springframework.web.servlet.ModelAndView; 19 | 20 | import br.com.casadocodigo.loja.models.PaymentData; 21 | import br.com.casadocodigo.loja.models.ShoppingCart; 22 | import br.com.casadocodigo.loja.models.SystemUser; 23 | 24 | @RestController 25 | @RequestMapping("/payment") 26 | public class PaymentController { 27 | 28 | @Autowired 29 | private ShoppingCart shoppingCart; 30 | @Autowired 31 | private RestTemplate restTemplate; 32 | @Autowired 33 | private MailSender mailer; 34 | 35 | @RequestMapping(value = "checkout", method = RequestMethod.POST) 36 | public Callable checkout(@AuthenticationPrincipal SystemUser user) { 37 | return () -> { 38 | BigDecimal total = shoppingCart.getTotal(); 39 | String uriToPay = "http://book-payment.herokuapp.com/payment"; 40 | try { 41 | restTemplate.postForObject(uriToPay, 42 | new PaymentData(total), String.class); 43 | sendNewPurchaseMail(user); 44 | return new ModelAndView("redirect:/payment/success"); 45 | } catch (HttpClientErrorException exception) { 46 | return new ModelAndView("redirect:/payment/error"); 47 | } 48 | 49 | }; 50 | } 51 | 52 | private void sendNewPurchaseMail(SystemUser user) { 53 | SimpleMailMessage email = new SimpleMailMessage(); 54 | email.setFrom("compras@casadocodigo.com.br"); 55 | email.setTo(user.getLogin()); 56 | email.setSubject("Nova compra"); 57 | email.setText("corpodo email"); 58 | mailer.send(email); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/ProductsController.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers; 2 | 3 | import java.io.IOException; 4 | 5 | import javax.transaction.Transactional; 6 | import javax.validation.Valid; 7 | 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.cache.annotation.CacheEvict; 10 | import org.springframework.cache.annotation.Cacheable; 11 | import org.springframework.stereotype.Controller; 12 | import org.springframework.validation.BindingResult; 13 | import org.springframework.web.bind.WebDataBinder; 14 | import org.springframework.web.bind.annotation.InitBinder; 15 | import org.springframework.web.bind.annotation.ModelAttribute; 16 | import org.springframework.web.bind.annotation.PathVariable; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestMethod; 19 | import org.springframework.web.multipart.MultipartFile; 20 | import org.springframework.web.servlet.ModelAndView; 21 | import org.springframework.web.servlet.mvc.support.RedirectAttributes; 22 | 23 | import br.com.casadocodigo.loja.daos.ProductDAO; 24 | import br.com.casadocodigo.loja.infra.FileSaver; 25 | import br.com.casadocodigo.loja.models.BookType; 26 | import br.com.casadocodigo.loja.models.Product; 27 | 28 | @Controller 29 | @Transactional 30 | @RequestMapping("/produtos") 31 | public class ProductsController { 32 | 33 | @Autowired 34 | private ProductDAO products; 35 | @Autowired 36 | private FileSaver fileSaver; 37 | 38 | @InitBinder 39 | protected void initBinder(WebDataBinder binder) { 40 | //binder.setValidator(new ProductValidator()); 41 | } 42 | 43 | 44 | @RequestMapping(method=RequestMethod.POST) 45 | @CacheEvict(value="lastProducts", allEntries=true) 46 | public ModelAndView save(MultipartFile summary,@ModelAttribute("product") @Valid Product product,BindingResult bindingResult,RedirectAttributes redirectAttributes) throws IOException{ 47 | if(bindingResult.hasErrors()){ 48 | return form(product); 49 | } 50 | 51 | //Sera que passo o product como parametro? 52 | String webPath = fileSaver.write("uploaded-images",summary); 53 | product.setSummaryPath(webPath); 54 | products.save(product); 55 | 56 | redirectAttributes.addFlashAttribute("success", "Produto cadastrado com sucesso"); 57 | return new ModelAndView("redirect:produtos"); 58 | } 59 | 60 | @RequestMapping("/form") 61 | public ModelAndView form(@ModelAttribute Product product){ 62 | ModelAndView modelAndView = new ModelAndView("products/form"); 63 | modelAndView.addObject("bookTypes", BookType.values()); 64 | return modelAndView; 65 | } 66 | 67 | @RequestMapping(method=RequestMethod.GET) 68 | @Cacheable(value="lastProducts") 69 | public ModelAndView list(){ 70 | ModelAndView modelAndView = new ModelAndView("products/list"); 71 | modelAndView.addObject("products", products.list()); 72 | return modelAndView; 73 | } 74 | 75 | 76 | @RequestMapping("/{id}") 77 | public ModelAndView show(@PathVariable("id") Integer id){ 78 | ModelAndView modelAndView = new ModelAndView("products/show"); 79 | Product product = products.find(id); 80 | modelAndView.addObject("product", product); 81 | return modelAndView; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/ShoppingCartController.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers; 2 | 3 | import org.springframework.beans.factory.annotation.Autowired; 4 | import org.springframework.stereotype.Controller; 5 | import org.springframework.web.bind.annotation.PathVariable; 6 | import org.springframework.web.bind.annotation.RequestMapping; 7 | import org.springframework.web.bind.annotation.RequestMethod; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.servlet.ModelAndView; 10 | 11 | import br.com.casadocodigo.loja.daos.ProductDAO; 12 | import br.com.casadocodigo.loja.models.BookType; 13 | import br.com.casadocodigo.loja.models.Product; 14 | import br.com.casadocodigo.loja.models.ShoppingCart; 15 | import br.com.casadocodigo.loja.models.ShoppingItem; 16 | 17 | @Controller 18 | @RequestMapping("/shopping") 19 | public class ShoppingCartController { 20 | 21 | @Autowired 22 | private ProductDAO productDAO; 23 | @Autowired 24 | private ShoppingCart shoppingCart; 25 | 26 | 27 | @RequestMapping(method=RequestMethod.POST) 28 | public ModelAndView add(Integer productId,@RequestParam BookType bookType){ 29 | ShoppingItem item = createItem(productId, bookType); 30 | shoppingCart.add(item); 31 | return new ModelAndView("redirect:/shopping"); 32 | } 33 | 34 | private ShoppingItem createItem(Integer productId, BookType bookType) { 35 | Product product = productDAO.find(productId); 36 | ShoppingItem item = new ShoppingItem(product,bookType); 37 | return item; 38 | } 39 | 40 | @RequestMapping(method=RequestMethod.GET) 41 | public String items(){ 42 | return "shoppingCart/items"; 43 | } 44 | 45 | @RequestMapping(method=RequestMethod.POST,value="/{productId}") 46 | public String remove(@PathVariable("productId") Integer productId,BookType bookType){ 47 | shoppingCart.remove(createItem(productId, bookType)); 48 | return "redirect:/shopping"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/integration/PaymentGateway.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers.integration; 2 | 3 | import java.io.IOException; 4 | import java.math.BigDecimal; 5 | import java.net.MalformedURLException; 6 | import java.net.URL; 7 | import java.util.UUID; 8 | import java.util.concurrent.Callable; 9 | 10 | import javax.servlet.http.HttpServletResponse; 11 | 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.http.HttpHeaders; 14 | import org.springframework.http.HttpStatus; 15 | import org.springframework.http.ResponseEntity; 16 | import org.springframework.web.bind.annotation.RequestBody; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.RequestMethod; 19 | import org.springframework.web.bind.annotation.RestController; 20 | import org.springframework.web.client.RestTemplate; 21 | 22 | import br.com.casadocodigo.loja.models.PaymentData; 23 | 24 | @RestController 25 | @RequestMapping("/gateway") 26 | public class PaymentGateway { 27 | 28 | //ab -r -n 600 -c 200 -p jsonData.txt -T 'application/json' http://localhost:8080/casadocodigo/gateway 29 | @SuppressWarnings({ "rawtypes", "unchecked" }) 30 | @RequestMapping(method = RequestMethod.POST,consumes="application/json") 31 | public ResponseEntity pay(@RequestBody PaymentData paymentData, HttpServletResponse response) 32 | throws InterruptedException, IOException { 33 | URL url = new URL("https://www.bing.com"); 34 | url.openStream(); 35 | HttpHeaders httpHeaders = new HttpHeaders(); 36 | if (paymentData.getValue().compareTo(new BigDecimal(500)) <= 0) { 37 | httpHeaders.add(HttpHeaders.LOCATION, "http://payment.com/" + UUID.randomUUID()); 38 | return new ResponseEntity(httpHeaders, HttpStatus.CREATED); 39 | } else { 40 | httpHeaders.add(HttpHeaders.LOCATION, "http://payment.com/fail/" + UUID.randomUUID()); 41 | return new ResponseEntity(httpHeaders, HttpStatus.BAD_REQUEST); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/controllers/integration/ProductsRestController.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers.integration; 2 | 3 | import java.util.List; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.cache.annotation.Cacheable; 7 | import org.springframework.http.MediaType; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestMethod; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | import br.com.casadocodigo.loja.daos.ProductDAO; 13 | import br.com.casadocodigo.loja.models.Product; 14 | 15 | @RestController 16 | //@RequestMapping(value = "/produtos", produces = MediaType.APPLICATION_JSON_VALUE) 17 | public class ProductsRestController { 18 | 19 | @Autowired 20 | private ProductDAO productDAO; 21 | 22 | // @RequestMapping(method = RequestMethod.GET) 23 | // @Cacheable(value = "lastProducts", keyGenerator = "headerKeyGenerator") 24 | public List listOtherFormats() { 25 | return productDAO.list(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/converters/StringToCalendarConverver.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.converters; 2 | 3 | import java.text.ParseException; 4 | import java.text.SimpleDateFormat; 5 | import java.util.Calendar; 6 | import java.util.Date; 7 | import java.util.HashSet; 8 | import java.util.Locale; 9 | import java.util.Set; 10 | 11 | import org.springframework.format.AnnotationFormatterFactory; 12 | import org.springframework.format.Formatter; 13 | import org.springframework.format.Parser; 14 | import org.springframework.format.Printer; 15 | import org.springframework.format.annotation.DateTimeFormat; 16 | import org.springframework.util.StringUtils; 17 | 18 | public class StringToCalendarConverver implements 19 | AnnotationFormatterFactory { 20 | 21 | @Override 22 | public Set> getFieldTypes() { 23 | HashSet> classes = new HashSet<>(); 24 | classes.add(Calendar.class); 25 | return classes; 26 | } 27 | 28 | @Override 29 | public Printer> getPrinter(DateTimeFormat annotation, Class> fieldType) { 30 | return new CalendarFormatter(annotation); 31 | } 32 | 33 | @Override 34 | public Parser> getParser(DateTimeFormat annotation, Class> fieldType) { 35 | return new CalendarFormatter(annotation); 36 | } 37 | 38 | private static class CalendarFormatter implements Formatter{ 39 | 40 | private SimpleDateFormat formatter; 41 | 42 | public CalendarFormatter(DateTimeFormat dateTimeFormat) { 43 | String pattern = dateTimeFormat.pattern(); 44 | if(!StringUtils.hasText(pattern)){ 45 | pattern = "yyyy-MM-dd"; 46 | } 47 | formatter = new SimpleDateFormat(pattern); 48 | } 49 | 50 | @Override 51 | public Calendar parse(String text, Locale locale) throws ParseException { 52 | Date date = formatter.parse(text); 53 | Calendar calendar = Calendar.getInstance(); 54 | calendar.setTime(date); 55 | return calendar; 56 | } 57 | 58 | @Override 59 | public String print(Calendar calendar, Locale locale) { 60 | return formatter.format(calendar.getTime()); 61 | } 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/daos/ProductDAO.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.daos; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | 6 | import javax.persistence.EntityManager; 7 | import javax.persistence.PersistenceContext; 8 | import javax.persistence.Query; 9 | import javax.persistence.TypedQuery; 10 | 11 | import org.springframework.stereotype.Repository; 12 | 13 | import br.com.casadocodigo.loja.models.BookType; 14 | import br.com.casadocodigo.loja.models.Product; 15 | 16 | @Repository 17 | public class ProductDAO { 18 | 19 | @PersistenceContext 20 | private EntityManager manager; 21 | 22 | public void save(Product produto) { 23 | manager.persist(produto); 24 | } 25 | 26 | public List list() { 27 | return manager.createQuery( 28 | "select p from Product p", 29 | Product.class).getResultList(); 30 | } 31 | 32 | public Product find(Integer id) { 33 | TypedQuery query = manager 34 | .createQuery( 35 | "select distinct(p) from Product p join fetch p.prices where p.id=:id", 36 | Product.class).setParameter("id", id); 37 | return query.getSingleResult(); 38 | } 39 | 40 | public Product findBy(Integer id, BookType bookType) { 41 | TypedQuery query = manager 42 | .createQuery( 43 | "select p from Product p join fetch p.prices price where p.id = :id and price.bookType = :bookType", 44 | Product.class); 45 | query.setParameter("id", id); 46 | query.setParameter("bookType", bookType); 47 | return query.getSingleResult(); 48 | } 49 | 50 | public BigDecimal sumPricesPerType(BookType bookType) { 51 | TypedQuery query = manager.createQuery( 52 | "select sum(price.value) from Product p join p.prices price where price.bookType =:bookType", 53 | BigDecimal.class); 54 | query.setParameter("bookType", bookType); 55 | return query.getSingleResult(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/daos/UserDAO.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.daos; 2 | 3 | import java.util.List; 4 | 5 | import javax.persistence.EntityManager; 6 | import javax.persistence.PersistenceContext; 7 | 8 | import org.springframework.security.core.userdetails.UserDetails; 9 | import org.springframework.security.core.userdetails.UserDetailsService; 10 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 11 | import org.springframework.stereotype.Repository; 12 | 13 | import br.com.casadocodigo.loja.models.SystemUser; 14 | 15 | @Repository 16 | public class UserDAO implements UserDetailsService{ 17 | 18 | @PersistenceContext 19 | private EntityManager em; 20 | 21 | @Override 22 | public UserDetails loadUserByUsername(String username) 23 | throws UsernameNotFoundException { 24 | String jpql = "select u from SystemUser u where u.login = :login"; 25 | List users = em.createQuery(jpql,SystemUser.class).setParameter("login", username).getResultList(); 26 | if(users.isEmpty()){ 27 | throw new UsernameNotFoundException("O usuario "+username+" não existe"); 28 | } 29 | return users.get(0); 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/infra/FileSaver.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.infra; 2 | 3 | import java.io.IOException; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Component; 7 | import org.springframework.web.multipart.MultipartFile; 8 | 9 | import com.amazonaws.AmazonClientException; 10 | import com.amazonaws.services.s3.AmazonS3Client; 11 | import com.amazonaws.services.s3.model.ObjectMetadata; 12 | 13 | @Component 14 | public class FileSaver { 15 | 16 | @Autowired 17 | private AmazonS3Client s3; 18 | 19 | public String write(String baseFolder, MultipartFile multipartFile) { 20 | try { 21 | s3.putObject("casadocodigo", multipartFile.getOriginalFilename(), 22 | multipartFile.getInputStream(), new ObjectMetadata()); 23 | return "http://localhost:9444/s3/casadocodigo/"+multipartFile.getOriginalFilename()+"?noAuth=true"; 24 | } catch (AmazonClientException | IOException e) { 25 | throw new RuntimeException(e); 26 | } 27 | 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/infra/HttpPartUtils.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.infra; 2 | 3 | import javax.servlet.http.Part; 4 | 5 | public class HttpPartUtils { 6 | 7 | public static String extractFileName(Part part) { 8 | String contentDisp = part.getHeader("content-disposition"); 9 | String[] items = contentDisp.split(";"); 10 | for (String s : items) { 11 | if (s.trim().startsWith("filename")) { 12 | return s.substring(s.indexOf("=") + 2, s.length()-1); 13 | } 14 | } 15 | return ""; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/infra/spring/SetAttributeScopeProcessor.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.infra.spring; 2 | 3 | import org.springframework.beans.BeansException; 4 | import org.springframework.beans.factory.config.BeanPostProcessor; 5 | import org.springframework.context.annotation.Scope; 6 | import org.springframework.web.context.request.RequestContextHolder; 7 | import org.springframework.web.context.request.WebRequest; 8 | 9 | public class SetAttributeScopeProcessor implements BeanPostProcessor { 10 | 11 | @Override 12 | public Object postProcessBeforeInitialization(Object bean, String beanName) 13 | throws BeansException { 14 | return bean; 15 | } 16 | 17 | @Override 18 | public Object postProcessAfterInitialization(Object bean, String beanName) 19 | throws BeansException { 20 | 21 | if (bean.getClass().getGenericSuperclass() instanceof Class) { 22 | Class> superClass = (Class>) bean.getClass() 23 | .getGenericSuperclass(); 24 | if (superClass.isAnnotationPresent(Scope.class)) { 25 | RequestContextHolder.currentRequestAttributes().setAttribute(beanName, bean, WebRequest.SCOPE_SESSION); 26 | } 27 | } 28 | return bean; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/BookType.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import javax.xml.bind.annotation.XmlRootElement; 4 | 5 | @XmlRootElement 6 | public enum BookType { 7 | 8 | EBOOK,PRINTED,COMBO 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/PaymentData.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class PaymentData { 6 | 7 | private BigDecimal value; 8 | 9 | public PaymentData() { 10 | } 11 | 12 | public PaymentData(BigDecimal value) { 13 | this.value = value; 14 | // TODO Auto-generated constructor stub 15 | } 16 | 17 | public BigDecimal getValue() { 18 | return value; 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/PaymentReturn.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | public class PaymentReturn { 4 | 5 | private String link; 6 | 7 | public PaymentReturn(String link) { 8 | this.link = link; 9 | } 10 | 11 | public String getLink() { 12 | return link; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/Price.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import java.math.BigDecimal; 4 | 5 | import javax.persistence.Column; 6 | import javax.persistence.Embeddable; 7 | import javax.xml.bind.annotation.XmlRootElement; 8 | 9 | @Embeddable 10 | @XmlRootElement 11 | public class Price { 12 | 13 | @Column(scale = 2) 14 | //@NumberFormat(style=Style.CURRENCY) 15 | private BigDecimal value; 16 | private BookType bookType; 17 | 18 | public BigDecimal getValue() { 19 | return value; 20 | } 21 | 22 | public void setValue(BigDecimal valor) { 23 | this.value = valor; 24 | } 25 | 26 | public BookType getBookType() { 27 | return bookType; 28 | } 29 | 30 | public void setBookType(BookType tipoLivro) { 31 | this.bookType = tipoLivro; 32 | } 33 | 34 | @Override 35 | public String toString() { 36 | return "Price [value=" + value + ", bookType=" + bookType + "]"; 37 | } 38 | 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/Product.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.ArrayList; 5 | import java.util.Calendar; 6 | import java.util.List; 7 | 8 | import javax.persistence.ElementCollection; 9 | import javax.persistence.Entity; 10 | import javax.persistence.GeneratedValue; 11 | import javax.persistence.GenerationType; 12 | import javax.persistence.Id; 13 | import javax.persistence.Lob; 14 | import javax.validation.constraints.Min; 15 | import javax.xml.bind.annotation.XmlRootElement; 16 | 17 | import org.hibernate.validator.constraints.NotBlank; 18 | import org.springframework.format.annotation.DateTimeFormat; 19 | import org.springframework.format.annotation.DateTimeFormat.ISO; 20 | 21 | @Entity 22 | @XmlRootElement 23 | public class Product { 24 | 25 | @Id 26 | @GeneratedValue(strategy = GenerationType.IDENTITY) 27 | private Integer id; 28 | @NotBlank 29 | private String title; 30 | @Lob 31 | @NotBlank 32 | private String description; 33 | @Min(30) 34 | private int pages; 35 | @ElementCollection 36 | private List prices = new ArrayList(); 37 | 38 | // motivar que eu quero fazer uma configuração global suportando este estilo 39 | // primeiro motiva que podemos criar um converter para isso. 40 | // @DateTimeFormat(iso=ISO.DATE) 41 | @DateTimeFormat 42 | private Calendar releaseDate; 43 | private String summaryPath; 44 | 45 | public String getSummaryPath() { 46 | return summaryPath; 47 | } 48 | 49 | public void setSummaryPath(String summaryPath) { 50 | this.summaryPath = summaryPath; 51 | } 52 | 53 | public Calendar getReleaseDate() { 54 | return releaseDate; 55 | } 56 | 57 | public void setReleaseDate(Calendar releaseDate) { 58 | this.releaseDate = releaseDate; 59 | } 60 | 61 | public Integer getId() { 62 | return id; 63 | } 64 | 65 | public List getPrices() { 66 | return prices; 67 | } 68 | 69 | public void setPrices(List valores) { 70 | this.prices = valores; 71 | } 72 | 73 | public String getTitle() { 74 | return title; 75 | } 76 | 77 | public void setTitle(String titulo) { 78 | this.title = titulo; 79 | } 80 | 81 | public String getDescription() { 82 | return description; 83 | } 84 | 85 | public void setDescription(String descricao) { 86 | this.description = descricao; 87 | } 88 | 89 | public int getPages() { 90 | return pages; 91 | } 92 | 93 | public void setPages(int numeroPaginas) { 94 | this.pages = numeroPaginas; 95 | } 96 | 97 | @Override 98 | public String toString() { 99 | return "Produto [id=" + id + ", titulo=" + title + ", descricao=" 100 | + description + ", numeroPaginas=" + pages + ", valores=" 101 | + prices + "]"; 102 | } 103 | 104 | public BigDecimal priceFor(BookType bookType) { 105 | return prices 106 | .stream() 107 | .filter(price -> price.getBookType().equals(bookType)) 108 | .findFirst().get().getValue(); 109 | } 110 | 111 | } 112 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/Role.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import javax.persistence.Entity; 4 | import javax.persistence.Id; 5 | 6 | import org.springframework.security.core.GrantedAuthority; 7 | 8 | @Entity 9 | public class Role implements GrantedAuthority { 10 | 11 | @Id 12 | private String name; 13 | 14 | @Deprecated 15 | private Role() { 16 | } 17 | 18 | private Role(String name) { 19 | this.name = name; 20 | } 21 | 22 | @Override 23 | public String getAuthority() { 24 | return name; 25 | } 26 | 27 | @Override 28 | public int hashCode() { 29 | final int prime = 31; 30 | int result = 1; 31 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 32 | return result; 33 | } 34 | 35 | @Override 36 | public boolean equals(Object obj) { 37 | if (this == obj) 38 | return true; 39 | if (obj == null) 40 | return false; 41 | if (getClass() != obj.getClass()) 42 | return false; 43 | Role other = (Role) obj; 44 | if (name == null) { 45 | if (other.name != null) 46 | return false; 47 | } else if (!name.equals(other.name)) 48 | return false; 49 | return true; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/ShoppingCart.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Collection; 5 | import java.util.LinkedHashMap; 6 | import java.util.Map; 7 | 8 | import org.springframework.context.annotation.Scope; 9 | import org.springframework.context.annotation.ScopedProxyMode; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.context.WebApplicationContext; 12 | 13 | @Component 14 | @Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS) 15 | public class ShoppingCart { 16 | 17 | private Map items = new LinkedHashMap(); 18 | 19 | public void add(ShoppingItem item) { 20 | items.put(item, getQuantity(item) + 1); 21 | } 22 | 23 | public Integer getQuantity(ShoppingItem item) { 24 | if (!items.containsKey(item)) { 25 | items.put(item, 0); 26 | } 27 | return items.get(item); 28 | } 29 | 30 | public Integer getQuantity() { 31 | return items.values().stream() 32 | .reduce(0, (next, accumulator) -> next + accumulator); 33 | } 34 | 35 | public Collection getList() { 36 | return items.keySet(); 37 | } 38 | 39 | public BigDecimal getTotal(ShoppingItem item) { 40 | return item.getTotal(getQuantity(item)); 41 | } 42 | 43 | public BigDecimal getTotal(){ 44 | BigDecimal total = BigDecimal.ZERO; 45 | //TODO change to reduce? 46 | for(ShoppingItem item : items.keySet()){ 47 | total = total.add(getTotal(item)); 48 | } 49 | return total; 50 | } 51 | 52 | public void remove(ShoppingItem shoppingItem) { 53 | items.remove(shoppingItem); 54 | } 55 | 56 | public boolean isEmpty() { 57 | return items.isEmpty(); 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/ShoppingItem.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.Arrays; 5 | 6 | public class ShoppingItem { 7 | 8 | private Product product; 9 | private BookType bookType; 10 | private Integer productId; 11 | 12 | public static ShoppingItem zeroed(){ 13 | Product product = new Product(); 14 | Price price = new Price(); 15 | BookType combo = BookType.COMBO; 16 | price.setBookType(combo); 17 | price.setValue(BigDecimal.ZERO); 18 | product.setPrices(Arrays.asList(price)); 19 | return new ShoppingItem(product, combo); 20 | } 21 | 22 | public ShoppingItem(Product product, BookType bookType) { 23 | this.product = product; 24 | this.bookType = bookType; 25 | this.productId = product.getId(); 26 | } 27 | 28 | public Product getProduct() { 29 | return product; 30 | } 31 | 32 | public BookType getBookType() { 33 | return bookType; 34 | } 35 | 36 | public BigDecimal getPrice(){ 37 | /** Navegue também até a classe Product, para descobrir como é a implementação do método priceFor **/ 38 | return product.priceFor(bookType); 39 | } 40 | 41 | @Override 42 | public int hashCode() { 43 | final int prime = 31; 44 | int result = 1; 45 | result = prime * result 46 | + ((bookType == null) ? 0 : bookType.hashCode()); 47 | result = prime * result 48 | + ((productId == null) ? 0 : productId.hashCode()); 49 | return result; 50 | } 51 | 52 | @Override 53 | public boolean equals(Object obj) { 54 | if (this == obj) 55 | return true; 56 | if (obj == null) 57 | return false; 58 | if (getClass() != obj.getClass()) 59 | return false; 60 | ShoppingItem other = (ShoppingItem) obj; 61 | if (bookType != other.bookType) 62 | return false; 63 | if (productId == null) { 64 | if (other.productId != null) 65 | return false; 66 | } else if (!productId.equals(other.productId)) 67 | return false; 68 | return true; 69 | } 70 | 71 | public BigDecimal getTotal(Integer quantity) { 72 | return getPrice().multiply(new BigDecimal(quantity)); 73 | } 74 | 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/models/SystemUser.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.models; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collection; 5 | import java.util.List; 6 | 7 | import javax.persistence.Entity; 8 | import javax.persistence.FetchType; 9 | import javax.persistence.Id; 10 | import javax.persistence.ManyToMany; 11 | import javax.persistence.Table; 12 | 13 | import org.springframework.security.core.GrantedAuthority; 14 | import org.springframework.security.core.userdetails.UserDetails; 15 | 16 | @Entity 17 | public class SystemUser implements UserDetails{ 18 | 19 | @Id 20 | private String login; 21 | private String password; 22 | private String name; 23 | @ManyToMany(fetch = FetchType.EAGER) 24 | private List roles = new ArrayList<>(); 25 | 26 | public String getLogin() { 27 | return login; 28 | } 29 | 30 | public void setLogin(String login) { 31 | this.login = login; 32 | } 33 | 34 | public String getPassword() { 35 | return password; 36 | } 37 | 38 | public void setPassword(String password) { 39 | this.password = password; 40 | } 41 | 42 | public String getName() { 43 | return name; 44 | } 45 | 46 | public void setName(String name) { 47 | this.name = name; 48 | } 49 | 50 | public List getRoles() { 51 | return roles; 52 | } 53 | 54 | public void setRoles(List roles) { 55 | this.roles = roles; 56 | } 57 | 58 | @Override 59 | public Collection extends GrantedAuthority> getAuthorities() { 60 | return roles; 61 | } 62 | 63 | @Override 64 | public String getUsername() { 65 | return login; 66 | } 67 | 68 | @Override 69 | public boolean isAccountNonExpired() { 70 | return true; 71 | } 72 | 73 | @Override 74 | public boolean isAccountNonLocked() { 75 | return true; 76 | } 77 | 78 | @Override 79 | public boolean isCredentialsNonExpired() { 80 | return true; 81 | } 82 | 83 | @Override 84 | public boolean isEnabled() { 85 | return true; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/tags/GenericInput.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.tags; 2 | 3 | import org.springframework.web.servlet.tags.form.InputTag; 4 | 5 | public class GenericInput extends InputTag{ 6 | 7 | private String type; 8 | 9 | public void setType(String type) { 10 | this.type = type; 11 | } 12 | 13 | @Override 14 | protected String getType() { 15 | return type; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/validacao/ProductValidator.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.validacao; 2 | 3 | import org.springframework.validation.Errors; 4 | import org.springframework.validation.ValidationUtils; 5 | import org.springframework.validation.Validator; 6 | 7 | import br.com.casadocodigo.loja.models.Product; 8 | 9 | public class ProductValidator implements Validator{ 10 | 11 | @Override 12 | public boolean supports(Class> clazz) { 13 | return Product.class.isAssignableFrom(clazz); 14 | } 15 | 16 | @Override 17 | public void validate(Object target, Errors errors) { 18 | // 19 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "titulo", "field.required"); 20 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "descricao", "field.required"); 21 | Product produto = (Product) target; 22 | if(produto.getPages() == 0){ 23 | errors.rejectValue("numeroPaginas", "field.required"); 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/viewresolver/CustomXMLViewResolver.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.viewresolver; 2 | 3 | import java.util.Locale; 4 | 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.oxm.Marshaller; 7 | import org.springframework.web.servlet.View; 8 | import org.springframework.web.servlet.ViewResolver; 9 | import org.springframework.web.servlet.view.xml.MarshallingView; 10 | 11 | public class CustomXMLViewResolver implements ViewResolver { 12 | 13 | private Marshaller marshaller; 14 | 15 | @Autowired 16 | public CustomXMLViewResolver(Marshaller marshaller) { 17 | this.marshaller = marshaller; 18 | } 19 | 20 | 21 | @Override 22 | public View resolveViewName(String viewName, Locale locale) 23 | throws Exception { 24 | MarshallingView view = new MarshallingView(); 25 | view.setMarshaller(marshaller); 26 | // view.setModelKey("products"); 27 | return view; 28 | } 29 | } -------------------------------------------------------------------------------- /src/main/java/br/com/casadocodigo/loja/viewresolver/JsonViewResolver.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.viewresolver; 2 | 3 | import java.util.Locale; 4 | 5 | import org.springframework.web.servlet.View; 6 | import org.springframework.web.servlet.ViewResolver; 7 | import org.springframework.web.servlet.view.json.MappingJackson2JsonView; 8 | 9 | public class JsonViewResolver implements ViewResolver { 10 | 11 | 12 | @Override 13 | public View resolveViewName(String viewName, Locale locale) throws Exception { 14 | MappingJackson2JsonView view = new MappingJackson2JsonView(); 15 | view.setPrettyPrint(true); 16 | return view; 17 | } 18 | } -------------------------------------------------------------------------------- /src/main/resources/log4j.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/403.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | Não autorizado 8 | 9 | 10 | Você não tem autorização para ver essa página 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/custom-form.tld: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | Custom tags 7 | 1.0 8 | customForm 9 | http://www.casadocodigo.com.br/tags/form 10 | 11 | 12 | Renders an HTML 'input' tag with type 'text' using the bound value. 13 | genericInput 14 | br.com.casadocodigo.loja.tags.GenericInput 15 | empty 16 | 17 | 18 | Type of the input 19 | type 20 | true 21 | true 22 | 23 | 24 | Path to property for data binding 25 | path 26 | true 27 | true 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/footer.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/livrospringmvc/lojacasadocodigo/b9c080493156b5ff3340363a115e0c42b4e80b29/src/main/webapp/WEB-INF/footer.jsp -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/header.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/livrospringmvc/lojacasadocodigo/b9c080493156b5ff3340363a115e0c42b4e80b29/src/main/webapp/WEB-INF/header.jsp -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/messages.properties: -------------------------------------------------------------------------------- 1 | field.required = Campo obrigatorio 2 | field.required.produto.titulo = Campo obrigatorio 3 | typeMismatch.produto.numeroPaginas = Digite um número 4 | typeMismatch.java.lang.Integer = Digite apenas números 5 | typeMismatch.int = Digite apenas numeros 6 | NotBlank.java.lang.String = Campo obrigatorio 7 | NotBlank.produto.titulo = Titulo obrigatório 8 | Min.produto.numeroPaginas = O numéro minimo de paginas é {1} 9 | 10 | #products 11 | products.list-title = Listagem de produtos 12 | navigation.category.agile = Agilidade 13 | navigation.category.front = Front end 14 | navigation.category.games = Jogos 15 | navigation.category.java = Java 16 | navigation.category.mobile = Desenvolvimento móvel 17 | navigation.category.web = Web 18 | navigation.category.others = Outros -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/messages_en_US.properties: -------------------------------------------------------------------------------- 1 | field.required = Campo obrigatorio 2 | field.required.produto.titulo = Campo obrigatorio 3 | typeMismatch.produto.numeroPaginas = Digite um n�mero 4 | typeMismatch.java.lang.Integer = Digite apenas n�meros 5 | typeMismatch.int = Digite apenas numeros 6 | NotBlank.java.lang.String = Campo obrigatorio 7 | NotBlank.produto.titulo = Titulo obrigat�rio 8 | Min.produto.numeroPaginas = O num�ro minimo de paginas � {1} 9 | 10 | #products 11 | products.list_title = List of products 12 | 13 | #shopping cart page 14 | shoppingCart.title = Shopping cart 15 | navigation.category.agile = Agile 16 | navigation.category.front = Front end 17 | navigation.category.games = Games 18 | navigation.category.java = Java 19 | navigation.category.mobile = Mobile 20 | navigation.category.web = Web 21 | navigation.category.others = Others 22 | 23 | users.welcome = Hello {0} -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/messages_pt.properties: -------------------------------------------------------------------------------- 1 | field.required = Campo obrigatorio 2 | field.required.produto.titulo = Campo obrigatorio 3 | typeMismatch.produto.numeroPaginas = Digite um n�mero 4 | typeMismatch.java.lang.Integer = Digite apenas n�meros 5 | typeMismatch.int = Digite apenas numeros 6 | NotBlank.java.lang.String = Campo obrigatorio 7 | NotBlank.produto.titulo = Titulo obrigat�rio 8 | Min.produto.numeroPaginas = O num�ro minimo de paginas � {1} 9 | 10 | #products 11 | products.list-title = Listagem brasileira de produtos 12 | 13 | shoppingCart.title = Carrinho 14 | navigation.category.agile = Agilidade 15 | navigation.category.front = Front end 16 | navigation.category.games = Jogos 17 | navigation.category.java = Java 18 | navigation.category.mobile = Desenvolvimento móvel 19 | navigation.category.web = Web 20 | navigation.category.others = Outros 21 | 22 | #users 23 | users.welcome = Olá {0} 24 | 25 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/tags/page.tag: -------------------------------------------------------------------------------- 1 | <%@attribute name="title" required="true" %> 2 | <%@attribute name="bodyClass" required="true" %> 3 | <%@attribute name="extraScripts" fragment="true" %> 4 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 5 | <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> 6 | <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 7 | <%@taglib uri="http://www.springframework.org/tags" prefix="spring" %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 20 | 21 | ${title} 22 | 23 | 24 | 25 | <%@include file="/WEB-INF/header.jsp" %> 26 | 27 | 28 | 29 | <%@include file="/WEB-INF/footer.jsp" %> 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/auth/login.jsp: -------------------------------------------------------------------------------- 1 | <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> 2 | 3 | 4 | Login Page 5 | 6 | 7 | Login with Username and Password 8 | 9 | 10 | 11 | User: 12 | 13 | 14 | 15 | Password: 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/hello-world.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | pageEncoding="UTF-8"%> 3 | 4 | 5 | 6 | 7 | Insert title here 8 | 9 | 10 | Ola! 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/products/form.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/livrospringmvc/lojacasadocodigo/b9c080493156b5ff3340363a115e0c42b4e80b29/src/main/webapp/WEB-INF/views/products/form.jsp -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/products/list.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | pageEncoding="UTF-8"%> 3 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 4 | <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> 5 | <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> 6 | <%@taglib tagdir="/WEB-INF/tags" prefix="customTags"%> 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | ${success} 16 | 17 | 18 | 19 | Cadastrar novo produto 20 | 21 | 22 | 23 | 24 | Titulo 25 | Valores 26 | 27 | 28 | 29 | ${product.title} 30 | 31 | 32 | [${price.value} - ${price.bookType}] 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/products/show.jsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/livrospringmvc/lojacasadocodigo/b9c080493156b5ff3340363a115e0c42b4e80b29/src/main/webapp/WEB-INF/views/products/show.jsp -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/views/shoppingCart/items.jsp: -------------------------------------------------------------------------------- 1 | <%@ page language="java" contentType="text/html; charset=UTF-8" 2 | pageEncoding="UTF-8"%> 3 | <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 4 | <%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%> 5 | <%@ taglib prefix="spring" uri="http://www.springframework.org/tags"%> 6 | <%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%> 7 | <%@taglib tagdir="/WEB-INF/tags" prefix="customTags"%> 8 | 9 | 10 | 11 | 12 | 24 | 25 | 26 | 28 | 29 | 30 | 50 | 51 | 52 | 53 | Seu carrinho de compras 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Item 66 | Preço 67 | Quantidade 68 | Total 69 | 70 | 71 | 72 | 73 | 74 | 75 | 77 | ${item.product.title}- 78 | ${item.bookType} 79 | ${item.price} 80 | 82 | ${shoppingCart.getTotal(item)} 83 | 85 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 97 | 99 | 100 | ${shoppingCart.total} 101 | 102 | 103 | 104 | 105 | 106 | Você já conhece os outros livros da Casa do Código? 107 | 108 | 111 | 114 | 115 | 119 | 122 | 123 | 129 | 130 | 134 | 137 | 138 | 141 | 144 | 145 | 146 | 147 | 148 | Veja todos os livros que 149 | publicamos! 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | casadocodigo 7 | 8 | 9 | 403 10 | /WEB-INF/403.jsp 11 | 12 | -------------------------------------------------------------------------------- /src/main/webapp/resources/js/jquery.js: -------------------------------------------------------------------------------- 1 | function test(){ 2 | 3 | } -------------------------------------------------------------------------------- /src/test/java/br/com/casadocodigo/loja/builders/ProductBuilder.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.builders; 2 | 3 | import java.awt.print.Book; 4 | import java.math.BigDecimal; 5 | import java.util.ArrayList; 6 | import java.util.Calendar; 7 | import java.util.List; 8 | 9 | import br.com.casadocodigo.loja.models.BookType; 10 | import br.com.casadocodigo.loja.models.Price; 11 | import br.com.casadocodigo.loja.models.Product; 12 | 13 | public class ProductBuilder { 14 | 15 | private List products = new ArrayList(); 16 | 17 | private ProductBuilder(Product product){ 18 | products.add(product); 19 | 20 | } 21 | 22 | public static ProductBuilder newProduct(BookType bookType,BigDecimal value){ 23 | Product book = create("Book 1",bookType, value); 24 | return new ProductBuilder(book); 25 | } 26 | 27 | public static ProductBuilder newProduct(){ 28 | Product book = create("Book 1",BookType.COMBO, BigDecimal.TEN); 29 | return new ProductBuilder(book); 30 | } 31 | 32 | private static Product create(String bookName,BookType bookType, BigDecimal value) { 33 | Product book = new Product(); 34 | book.setTitle(bookName); 35 | book.setReleaseDate(Calendar.getInstance()); 36 | book.setPages(150); 37 | book.setDescription("great book about testing"); 38 | Price price = new Price(); 39 | price.setBookType(bookType); 40 | price.setValue(value); 41 | book.getPrices().add(price); 42 | return book; 43 | } 44 | 45 | public ProductBuilder more(int number){ 46 | Product base = products.get(0); 47 | Price price = base.getPrices().get(0); 48 | for (int i = 0; i < number; i++) { 49 | products.add(create("Book "+i, price.getBookType(), price.getValue())); 50 | } 51 | return this; 52 | } 53 | 54 | public Product buildOne() { 55 | return products.get(0); 56 | } 57 | 58 | public List buildAll(){ 59 | return products; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/br/com/casadocodigo/loja/conf/DataSourceConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.conf; 2 | 3 | import javax.sql.DataSource; 4 | 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Profile; 7 | import org.springframework.jdbc.datasource.DriverManagerDataSource; 8 | 9 | public class DataSourceConfigurationTest { 10 | 11 | @Bean 12 | @Profile("test") 13 | public DataSource dataSource(){ 14 | DriverManagerDataSource dataSource = new DriverManagerDataSource(); 15 | dataSource.setDriverClassName("com.mysql.jdbc.Driver"); 16 | dataSource.setUrl("jdbc:mysql://localhost:3306/casadocodigo_test"); 17 | dataSource.setUsername( "root" ); 18 | dataSource.setPassword( "" ); 19 | return dataSource; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/test/java/br/com/casadocodigo/loja/controllers/ProductsControllerTest.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.controllers; 2 | 3 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 4 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 5 | 6 | import java.math.BigDecimal; 7 | import java.util.Calendar; 8 | import java.util.List; 9 | 10 | import javax.servlet.Filter; 11 | import javax.transaction.Transactional; 12 | 13 | import org.junit.Assert; 14 | import org.junit.Before; 15 | import org.junit.Test; 16 | import org.junit.runner.RunWith; 17 | import org.springframework.beans.factory.annotation.Autowired; 18 | import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; 19 | import org.springframework.test.annotation.Rollback; 20 | import org.springframework.test.annotation.Timed; 21 | import org.springframework.test.context.ActiveProfiles; 22 | import org.springframework.test.context.ContextConfiguration; 23 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 24 | import org.springframework.test.context.web.WebAppConfiguration; 25 | import org.springframework.test.web.servlet.MockMvc; 26 | import org.springframework.test.web.servlet.MvcResult; 27 | import org.springframework.test.web.servlet.ResultActions; 28 | import org.springframework.test.web.servlet.ResultMatcher; 29 | import org.springframework.test.web.servlet.result.MockMvcResultMatchers; 30 | import org.springframework.test.web.servlet.setup.MockMvcBuilders; 31 | import org.springframework.web.context.WebApplicationContext; 32 | import org.springframework.web.servlet.ModelAndView; 33 | 34 | import br.com.casadocodigo.loja.builders.ProductBuilder; 35 | import br.com.casadocodigo.loja.conf.AppWebConfiguration; 36 | import br.com.casadocodigo.loja.conf.DataSourceConfigurationTest; 37 | import br.com.casadocodigo.loja.conf.JPAConfiguration; 38 | import br.com.casadocodigo.loja.conf.SecurityConfiguration; 39 | import br.com.casadocodigo.loja.daos.ProductDAO; 40 | import br.com.casadocodigo.loja.models.BookType; 41 | import br.com.casadocodigo.loja.models.Price; 42 | import br.com.casadocodigo.loja.models.Product; 43 | 44 | @RunWith(SpringJUnit4ClassRunner.class) 45 | @WebAppConfiguration 46 | @ContextConfiguration(classes = { AppWebConfiguration.class, 47 | JPAConfiguration.class, SecurityConfiguration.class, 48 | DataSourceConfigurationTest.class }) 49 | @ActiveProfiles("test") 50 | public class ProductsControllerTest { 51 | 52 | @Autowired 53 | private WebApplicationContext wac; 54 | 55 | private MockMvc mockMvc; 56 | 57 | // pq tem apenas esse filtro 58 | @Autowired 59 | private Filter springSecurityFilterChain; 60 | @Autowired 61 | private ProductDAO productDAO; 62 | 63 | @Before 64 | public void setup() { 65 | this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) 66 | .addFilters(springSecurityFilterChain).build(); 67 | } 68 | 69 | @Test 70 | public void onlyAdminShoudAccessProductsForm() 71 | throws Exception { 72 | // poderia usar o isFound() 73 | this.mockMvc.perform( 74 | get("/produtos/form").with( 75 | SecurityMockMvcRequestPostProcessors 76 | .user("comprador@gmail.com").password("123456") 77 | .roles("COMPRADOR"))).andExpect( 78 | status().is(403)); 79 | } 80 | 81 | // verificar que os produtos estão sendo exibidos na lista 82 | @Test 83 | @Transactional 84 | public void shouldListAllBooksInTheHome() 85 | throws Exception { 86 | productDAO.save(ProductBuilder.newProduct().buildOne()); 87 | 88 | ResultActions action = this.mockMvc.perform(get("/produtos")); 89 | ResultMatcher modelAndViewMatcher = new ResultMatcher() { 90 | 91 | @Override 92 | public void match(MvcResult result) throws Exception { 93 | ModelAndView mv = result.getModelAndView(); 94 | List products = (List) mv.getModel().get("products"); 95 | Assert.assertEquals(1, products.size()); 96 | } 97 | }; 98 | action.andExpect(modelAndViewMatcher).andExpect( 99 | MockMvcResultMatchers 100 | .forwardedUrl("/WEB-INF/views/products/list.jsp")); 101 | 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/test/java/br/com/casadocodigo/loja/daos/ProductDAOTest.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.daos; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | 6 | import javax.transaction.Transactional; 7 | 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.test.context.ActiveProfiles; 13 | import org.springframework.test.context.ContextConfiguration; 14 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; 15 | 16 | import br.com.casadocodigo.loja.builders.ProductBuilder; 17 | import br.com.casadocodigo.loja.conf.DataSourceConfigurationTest; 18 | import br.com.casadocodigo.loja.conf.JPAConfiguration; 19 | import br.com.casadocodigo.loja.models.BookType; 20 | import br.com.casadocodigo.loja.models.Product; 21 | 22 | @RunWith(SpringJUnit4ClassRunner.class) 23 | @ContextConfiguration(classes = {ProductDAO.class,JPAConfiguration.class,DataSourceConfigurationTest.class }) 24 | @ActiveProfiles("test") 25 | public class ProductDAOTest { 26 | 27 | @Autowired 28 | private ProductDAO productDAO; 29 | 30 | @Transactional 31 | @Test 32 | public void shouldSumAllPricesOfEachBookPerType() { 33 | 34 | List printedBooks = ProductBuilder 35 | .newProduct(BookType.PRINTED, BigDecimal.TEN).more(4) 36 | .buildAll(); 37 | printedBooks.stream().forEach(productDAO::save); 38 | 39 | List ebooks = ProductBuilder 40 | .newProduct(BookType.EBOOK, BigDecimal.TEN).more(4).buildAll(); 41 | ebooks.stream().forEach(productDAO::save); 42 | BigDecimal value = productDAO.sumPricesPerType(BookType.PRINTED); 43 | Assert.assertEquals(new BigDecimal(50).setScale(2), value); 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/test/java/br/com/casadocodigo/loja/infra/FileSaverTest.java: -------------------------------------------------------------------------------- 1 | package br.com.casadocodigo.loja.infra; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | 7 | import com.amazonaws.ClientConfiguration; 8 | import com.amazonaws.auth.AWSCredentials; 9 | import com.amazonaws.auth.BasicAWSCredentials; 10 | import com.amazonaws.services.s3.AmazonS3Client; 11 | import com.amazonaws.services.s3.S3ClientOptions; 12 | import com.amazonaws.services.s3.model.ObjectMetadata; 13 | import com.amazonaws.services.s3.model.PutObjectResult; 14 | 15 | public class FileSaverTest { 16 | 17 | public static void main(String[] args) throws FileNotFoundException { 18 | AWSCredentials credentials = new BasicAWSCredentials("AKIAIOSFODNN7EXAMPLE", "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"); 19 | AmazonS3Client newClient = new AmazonS3Client(credentials, 20 | new ClientConfiguration()); 21 | newClient.setS3ClientOptions(new S3ClientOptions().withPathStyleAccess(true)); 22 | newClient.setEndpoint("http://localhost:9444/s3"); 23 | FileInputStream file = new FileInputStream(new File("/Users/alberto/Desktop/s3ninja-sempasta.png")); 24 | PutObjectResult putObject = newClient.putObject("casadocodigo", "arquivo.java", file, new ObjectMetadata()); 25 | 26 | } 27 | } 28 | --------------------------------------------------------------------------------