Skip to content

Commit aff0bf7

Browse files
committed
CategoryController.showInfo(): replace Category by LinkEntityDto.
Addressed to #120 No functional changes.
1 parent aa826c2 commit aff0bf7

File tree

12 files changed

+211
-3
lines changed

12 files changed

+211
-3
lines changed

src/main/java/ru/mystamps/web/config/MvcConfig.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.springframework.context.annotation.Import;
2727
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
2828
import org.springframework.data.repository.support.DomainClassConverter;
29+
import org.springframework.format.FormatterRegistry;
2930
import org.springframework.format.support.FormattingConversionService;
3031
import org.springframework.scheduling.annotation.EnableScheduling;
3132
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
@@ -40,6 +41,7 @@
4041
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
4142
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
4243

44+
import ru.mystamps.web.support.spring.mvc.converter.LinkEntityDtoConverter;
4345
import ru.mystamps.web.support.spring.security.CustomUserDetailsArgumentResolver;
4446
import ru.mystamps.web.Url;
4547
import ru.mystamps.web.support.spring.security.UserArgumentResolver;
@@ -49,6 +51,14 @@
4951
@Import(ControllersConfig.class)
5052
public class MvcConfig extends WebMvcConfigurerAdapter {
5153

54+
@Autowired
55+
private ServicesConfig servicesConfig;
56+
57+
@Override
58+
public void addFormatters(FormatterRegistry registry) {
59+
registry.addConverter(new LinkEntityDtoConverter(servicesConfig.getCategoryService()));
60+
}
61+
5262
@Override
5363
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
5464
configurer.enable();

src/main/java/ru/mystamps/web/controller/CategoryController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@
3838
import lombok.RequiredArgsConstructor;
3939

4040
import ru.mystamps.web.Url;
41-
import ru.mystamps.web.entity.Category;
4241
import ru.mystamps.web.entity.User;
4342
import ru.mystamps.web.model.AddCategoryForm;
4443
import ru.mystamps.web.service.CategoryService;
4544
import ru.mystamps.web.service.SeriesService;
45+
import ru.mystamps.web.service.dto.LinkEntityDto;
4646
import ru.mystamps.web.service.dto.UrlEntityDto;
47+
import ru.mystamps.web.support.spring.mvc.converter.annotation.Category;
4748
import ru.mystamps.web.util.LocaleUtils;
4849

4950
@Controller
@@ -89,7 +90,7 @@ public String processInput(
8990

9091
@RequestMapping(Url.INFO_CATEGORY_PAGE)
9192
public String showInfo(
92-
@PathVariable("id") Category category,
93+
@Category @PathVariable("id") LinkEntityDto category,
9394
Model model,
9495
Locale userLocale,
9596
HttpServletResponse response)
@@ -102,7 +103,7 @@ public String showInfo(
102103

103104
model.addAttribute("categoryId", category.getId());
104105
model.addAttribute("categorySlug", category.getSlug());
105-
model.addAttribute("categoryName", LocaleUtils.getLocalizedName(userLocale, category));
106+
model.addAttribute("categoryName", category.getName());
106107

107108
String lang = LocaleUtils.getLanguageOrNull(userLocale);
108109
Integer categoryId = category.getId();

src/main/java/ru/mystamps/web/dao/JdbcCategoryDao.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ public interface JdbcCategoryDao {
3232
Map<String, Integer> getStatisticsOf(Integer collectionId, String lang);
3333
Iterable<SelectEntityDto> findAllAsSelectEntities(String lang);
3434
Iterable<LinkEntityDto> findAllAsLinkEntities(String lang);
35+
LinkEntityDto findOneAsLinkEntity(Integer categoryId, String lang);
3536
}

src/main/java/ru/mystamps/web/dao/impl/JdbcCategoryDaoImpl.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.commons.lang3.Validate;
2626

2727
import org.springframework.beans.factory.annotation.Value;
28+
import org.springframework.dao.EmptyResultDataAccessException;
2829
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
2930
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
3031
import org.springframework.jdbc.support.GeneratedKeyHolder;
@@ -38,6 +39,7 @@
3839
import ru.mystamps.web.service.dto.SelectEntityDto;
3940

4041
@RequiredArgsConstructor
42+
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
4143
public class JdbcCategoryDaoImpl implements JdbcCategoryDao {
4244

4345
private final NamedParameterJdbcTemplate jdbcTemplate;
@@ -66,6 +68,9 @@ public class JdbcCategoryDaoImpl implements JdbcCategoryDao {
6668
@Value("${category.find_all_categories_names_with_slug}")
6769
private String findCategoriesNamesWithSlugSql;
6870

71+
@Value("${category.find_category_link_info_by_id}")
72+
private String findCategoryLinkEntityByIdSql;
73+
6974
@Override
7075
public Integer add(AddCategoryDbDto category) {
7176
Map<String, Object> params = new HashMap<>();
@@ -169,4 +174,21 @@ public Iterable<LinkEntityDto> findAllAsLinkEntities(String lang) {
169174
);
170175
}
171176

177+
@Override
178+
public LinkEntityDto findOneAsLinkEntity(Integer categoryId, String lang) {
179+
Map<String, Object> params = new HashMap<>();
180+
params.put("category_id", categoryId);
181+
params.put("lang", lang);
182+
183+
try {
184+
return jdbcTemplate.queryForObject(
185+
findCategoryLinkEntityByIdSql,
186+
params,
187+
RowMappers::forLinkEntityDto
188+
);
189+
} catch (EmptyResultDataAccessException ignored) {
190+
return null;
191+
}
192+
}
193+
172194
}

src/main/java/ru/mystamps/web/service/CategoryService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public interface CategoryService {
2828
UrlEntityDto add(AddCategoryDto dto, Integer userId);
2929
Iterable<SelectEntityDto> findAllAsSelectEntities(String lang);
3030
Iterable<LinkEntityDto> findAllAsLinkEntities(String lang);
31+
LinkEntityDto findOneAsLinkEntity(Integer categoryId, String lang);
3132
long countAll();
3233
long countCategoriesOf(Integer collectionId);
3334
long countByName(String name);

src/main/java/ru/mystamps/web/service/CategoryServiceImpl.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ public Iterable<LinkEntityDto> findAllAsLinkEntities(String lang) {
9090
return categoryDao.findAllAsLinkEntities(lang);
9191
}
9292

93+
@Override
94+
@Transactional(readOnly = true)
95+
public LinkEntityDto findOneAsLinkEntity(Integer categoryId, String lang) {
96+
Validate.isTrue(categoryId != null, "Category id must be non null");
97+
98+
return categoryDao.findOneAsLinkEntity(categoryId, lang);
99+
}
100+
93101
@Override
94102
@Transactional(readOnly = true)
95103
public long countAll() {
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (C) 2009-2015 Slava Semushin <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
package ru.mystamps.web.support.spring.mvc.converter;
19+
20+
import org.slf4j.Logger;
21+
import org.slf4j.LoggerFactory;
22+
23+
import org.springframework.core.convert.TypeDescriptor;
24+
import org.springframework.core.convert.converter.ConditionalConverter;
25+
import org.springframework.core.convert.converter.Converter;
26+
27+
import lombok.RequiredArgsConstructor;
28+
29+
import ru.mystamps.web.service.CategoryService;
30+
import ru.mystamps.web.service.dto.LinkEntityDto;
31+
import ru.mystamps.web.support.spring.mvc.converter.annotation.Category;
32+
import ru.mystamps.web.util.LocaleUtils;
33+
34+
@RequiredArgsConstructor
35+
public class LinkEntityDtoConverter
36+
implements Converter<String, LinkEntityDto>, ConditionalConverter {
37+
38+
private static final Logger LOG = LoggerFactory.getLogger(LinkEntityDtoConverter.class);
39+
40+
private final CategoryService categoryService;
41+
42+
@Override
43+
public LinkEntityDto convert(String value) {
44+
String lang = LocaleUtils.getCurrentLanguageOrNull();
45+
46+
try {
47+
Integer id = Integer.valueOf(value);
48+
if (id <= 0) {
49+
LOG.warn("Attempt to convert non positive number ({})", id);
50+
return null;
51+
}
52+
53+
return categoryService.findOneAsLinkEntity(id, lang);
54+
55+
} catch (NumberFormatException ex) {
56+
LOG.warn("Can't convert value '{}' from string to integer: {}", value, ex.getMessage());
57+
return null;
58+
}
59+
}
60+
61+
@Override
62+
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType) {
63+
if (targetType == null) {
64+
LOG.warn("Can't determine whether type matches or not because target type is null");
65+
return false;
66+
}
67+
68+
return targetType.hasAnnotation(Category.class);
69+
}
70+
71+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright (C) 2009-2015 Slava Semushin <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation; either version 2 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program; if not, write to the Free Software
16+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
package ru.mystamps.web.support.spring.mvc.converter.annotation;
19+
20+
import java.lang.annotation.Documented;
21+
import java.lang.annotation.ElementType;
22+
import java.lang.annotation.Retention;
23+
import java.lang.annotation.RetentionPolicy;
24+
import java.lang.annotation.Target;
25+
26+
@Target(ElementType.PARAMETER)
27+
@Retention(RetentionPolicy.RUNTIME)
28+
@Documented
29+
public @interface Category {
30+
}

src/main/java/ru/mystamps/web/util/LocaleUtils.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
import org.apache.commons.lang3.Validate;
2323

24+
import org.springframework.context.i18n.LocaleContext;
25+
import org.springframework.context.i18n.LocaleContextHolder;
26+
2427
import ru.mystamps.web.entity.LocalizedEntity;
2528

2629
public final class LocaleUtils {
@@ -40,6 +43,18 @@ public static String getLanguageOrDefault(Locale locale, String defaultValue) {
4043
return locale.getLanguage();
4144
}
4245

46+
// Our version of LocaleContextHolder.getLocale() that
47+
// doesn't fallback to the system default locale and
48+
// returns string representation of locale.
49+
public static String getCurrentLanguageOrNull() {
50+
LocaleContext localeContext = LocaleContextHolder.getLocaleContext();
51+
if (localeContext == null) {
52+
return null;
53+
}
54+
55+
return getLanguageOrNull(localeContext.getLocale());
56+
}
57+
4358
public static String getLocalizedName(Locale locale, LocalizedEntity entity) {
4459
Validate.isTrue(entity != null, "LocalizedEntity must be non null");
4560

src/main/resources/sql/category_dao_queries.properties

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,11 @@ category.find_all_categories_names_with_slug = \
6363
, c.id \
6464
FROM categories c \
6565
ORDER BY CASE WHEN 'ru' = :lang THEN c.name_ru ELSE c.name END
66+
67+
category.find_category_link_info_by_id = \
68+
SELECT CASE WHEN 'ru' = :lang THEN c.name_ru ELSE c.name END AS name \
69+
, c.slug \
70+
, c.id \
71+
FROM categories c \
72+
WHERE c.id = :category_id \
73+
ORDER BY CASE WHEN 'ru' = :lang THEN c.name_ru ELSE c.name END

src/test/groovy/ru/mystamps/web/service/CategoryServiceImplTest.groovy

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,41 @@ class CategoryServiceImplTest extends Specification {
259259
null | _
260260
}
261261

262+
//
263+
// Tests for findOneAsLinkEntity()
264+
//
265+
266+
def "findOneAsLinkEntity() should throw exception when category id is null"() {
267+
when:
268+
service.findOneAsLinkEntity(null, 'ru')
269+
then:
270+
thrown IllegalArgumentException
271+
}
272+
273+
def "findOneAsLinkEntity() should pass arguments to dao"() {
274+
given:
275+
Integer expectedCategoryId = 15
276+
and:
277+
String expectedLang = 'fr'
278+
and:
279+
LinkEntityDto expectedDto = TestObjects.createLinkEntityDto()
280+
when:
281+
LinkEntityDto actualDto = service.findOneAsLinkEntity(expectedCategoryId, expectedLang)
282+
then:
283+
1 * categoryDao.findOneAsLinkEntity(
284+
{ Integer categoryId ->
285+
assert expectedCategoryId == categoryId
286+
return true
287+
},
288+
{ String lang ->
289+
assert expectedLang == lang
290+
return true
291+
}
292+
) >> expectedDto
293+
and:
294+
actualDto == expectedDto
295+
}
296+
262297
//
263298
// Tests for countAll()
264299
//

src/test/java/ru/mystamps/web/service/TestObjects.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import ru.mystamps.web.entity.User;
3434
import ru.mystamps.web.entity.UsersActivation;
3535
import ru.mystamps.web.service.dto.DbImageDto;
36+
import ru.mystamps.web.service.dto.LinkEntityDto;
3637
import ru.mystamps.web.service.dto.SitemapInfoDto;
3738
import ru.mystamps.web.service.dto.UrlEntityDto;
3839
import ru.mystamps.web.util.SlugUtils;
@@ -53,6 +54,7 @@ final class TestObjects {
5354
private static final String TEST_LOGIN = "test";
5455

5556
private static final Integer TEST_ENTITY_ID = 456;
57+
private static final String TEST_ENTITY_NAME = TEST_NAME;
5658
private static final String TEST_ENTITY_SLUG = "test-slug";
5759

5860
// CheckStyle: ignore LineLength for next 1 line
@@ -87,6 +89,10 @@ public static UrlEntityDto createUrlEntityDto() {
8789
return new UrlEntityDto(TEST_ENTITY_ID, TEST_ENTITY_SLUG);
8890
}
8991

92+
public static LinkEntityDto createLinkEntityDto() {
93+
return new LinkEntityDto(TEST_ENTITY_ID, TEST_ENTITY_SLUG, TEST_ENTITY_NAME);
94+
}
95+
9096
public static User createUser() {
9197
final Integer anyId = 777;
9298
User user = new User();

0 commit comments

Comments
 (0)