简体   繁体   English

Spring Controller / Service / Repository中的泛型

[英]Generics in Spring Controller/Service/Repository

I would like to trim down my code to use only one function for filtering. 我想减少我的代码只使用一个函数进行过滤。 Filtering should work with 3 different classes: com.example.model.Category, com.example.model.Tag, java.util.Calendar. 过滤应该使用3个不同的类:com.example.model.Category,com.example.model.Tag,java.util.Calendar。

Here's my Controller 这是我的控制器

@Controller
@RequestMapping( "/blog" )
public class BlogController
{
    @Autowired
    private ArticleService articleService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private TagService tagService;

    private static final int PER_PAGE = 5;

    private static final int ARCHIVE_MONTHS = 12;

    @ModelAttribute
    public void addGlobalObjects( Map<String, Object> map )
    {
        map.put( "section", "blog" );

        SortedMap<Category, Integer> categories = new TreeMap<Category, Integer>();
        for ( Category category : categoryService.list() )
        {
            categories.put( category, articleService.size( category, Category.class ) );
        }

        Calendar cal = Calendar.getInstance();
        cal.set( Calendar.DAY_OF_MONTH, 1 );

        cal.add( Calendar.MONTH, ARCHIVE_MONTHS * -1 );

        SortedMap<Date, Integer> archive = new TreeMap<Date, Integer>();
        for ( int i = 0; i < ARCHIVE_MONTHS; ++i )
        {
            cal.add( Calendar.MONTH, 1 );
            archive.put( cal.getTime(), articleService.size( cal, Calendar.class ) );
        }

        SortedMap<Tag, Integer> tags = new TreeMap<Tag, Integer>();
        for ( Tag tag : tagService.list() )
        {
            tags.put( tag, articleService.size( tag, Tag.class ) );
        }

        map.put( "categories", categories );
        map.put( "archive", archive );
        map.put( "tags", tags );

        map.put( "categoriesSize", categoryService.size() );
        map.put( "tagsSize", tagService.size() );

        map.put( "date", new Date() );
    }

    @RequestMapping( "/index.html" )
    public String index( HttpServletRequest request, Map<String, Object> map )
    {
        return list( request, map, null, null );
    }

    @RequestMapping( "/archive/{date}.html" )
    public String archive( @PathVariable( "date" ) @DateTimeFormat( iso = ISO.DATE, style = "yyyy/MM" ) Date date, HttpServletRequest request, Map<String, Object> map )
    {
        Calendar cal = Calendar.getInstance();
        cal.setTime( date );

        return list( request, map, cal, Calendar.class );
    }

    private <T> String list( HttpServletRequest request, Map<String, Object> map, Object filterObject, Class<T> clazz )
    {
        int page = ServletRequestUtils.getIntParameter( request, "page", 1 );
        map.put( "articles", articleService.list( page * PER_PAGE - PER_PAGE, PER_PAGE, filterObject, clazz ) );
        map.put( "numPages", Math.ceil( articleService.size() / PER_PAGE ) );
        map.put( "currentPage", page );
        return "articles";
    }
}

In my ArticleDAO now I need to implement the methods list/size: 在我的ArticleDAO中,我现在需要实现方法列表/大小:

@Repository
public class ArticleDAO extends BaseDAO<Article>
{
    public <T> List<Article> list( int offset, int limit, Object filterObject, Class<T> clazz )
    {
        Criteria c = doFilter( filterObject, clazz );

        if ( limit > 0 )
        {
            c.setFirstResult( offset );
            c.setMaxResults( limit );
        }

        return c.list();
    }

    public <T> Integer size( Object filterObject, Class<T> clazz )
    {
        Number ret = ( Number ) doFilter( filterObject, clazz ).setProjection( Projections.rowCount() ).uniqueResult();
        return ret.intValue();
    }

    private <T> Criteria doFilter( Object filterObject, Class<T> clazz )
    {
        Criteria criteria = sessionFactory.getCurrentSession().createCriteria( Article.class );

        if ( filterObject != null && clazz != null )
        {
            T filter = clazz.cast( filterObject );

            if ( filter instanceof Calendar )
            {
                // The method set(int, int) is undefined for the type T
                filter.set( Calendar.DAY_OF_MONTH, 1 );
                filter.set( Calendar.HOUR_OF_DAY, 0 );
                filter.set( Calendar.MINUTE, 0 );
                filter.set( Calendar.SECOND, 0 );
                // The method getTime() is undefined for the type T
                Date d1 = filter.getTime();

                // The method getActualMaximum(int) is undefined for the type T
                filter.set( Calendar.DAY_OF_MONTH, filter.getActualMaximum( Calendar.DAY_OF_MONTH ) );
                filter.set( Calendar.HOUR_OF_DAY, 23 );
                filter.set( Calendar.MINUTE, 59 );
                filter.set( Calendar.SECOND, 59 );
                Date d2 = filter.getTime();

                criteria.add( Restrictions.between( "creationDate", d1, d2 ) );
            }

            if ( filter instanceof Category )
            {
                // The method getId() is undefined for the type T
                criteria.createCriteria( "categories" ).add( Restrictions.eq( "id", filter.getId() ) );
            }

            if ( filter instanceof Tag )
            {
                // The method getId() is undefined for the type T
                criteria.createCriteria( "tags" ).add( Restrictions.eq( "id", filter.getId() ) );
            }
        }

        return criteria;
    }
}

How ArticleDAO.doFilter should look like? ArticleDAO.doFilter应该如何? I guess I don't understand the Generics stuff. 我想我不懂Generics的东西。

I don't think generics is buying you anything here. 我不认为仿制药在这里买你什么。 This won't even compile b/c T is not known and you are trying to call specific methods (eg getId()). 这甚至不会编译b / c T未知并且您正在尝试调用特定方法(例如getId())。

There are a few ways you can do this without generics. 没有泛型,有几种方法可以做到这一点。 The simplest way would be 最简单的方法是

 if ( filterObject instanceof Calendar ) {
   Calendar filterCal = (Calendar) filterObject;

   filterCal.set (Calendar.DAY_OF_MONTH, 1); // ... and so on

If you do it this way, you can drop the clazz parameter from your methods. 如果以这种方式执行,则可以从方法中删除clazz参数。 You don't need that clazz.cast() call. 你不需要clazz.cast()调用。

Just a word on generics, I typically find myself using generics when I am doing the same thing regardless of the type. 只是关于泛型的一个词,我通常会发现自己在使用泛型时,无论类型如何都在做同样的事情。 For instance, it looks like you are using generics successfully for your BaseDAO. 例如,看起来您正在为BaseDAO成功使用泛型。 Regardless of the type, BaseDAO saves, updates, deletes, etc. In your case above, you are trying to do something different based on type. 无论类型如何,BaseDAO都会保存,更新,删除等。在您的上述情况中,您尝试根据类型执行不同的操作。 It doesn't really lend itself to generics. 它并不适用于泛型。 In fact, doing something different per type usually means you can do it nicely with polymorphism. 事实上,每种类型做一些不同的事情通常意味着你可以很好地利用多态性。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用Spring从控制器层调用存储库和服务 - Call repository and service from controller layer with Spring 带有控制器的单元测试Spring Boot-&gt;服务-&gt;存储库 - Unit Test Spring Boot with Controller -> Service -> Repository Spring &amp; Java 泛型 - 在抽象控制器中获取一项服务的实例 - Spring & Java Generics - Getting instance of one service in abstract controller 在Spring中使用泛型生成服务 - generate service with generics in Spring Spring Data Repository 不适用于泛型 - Spring Data Repository not working with Generics Spring @Repository和@Service - Spring @Repository and @Service Spring NoSuchBeanDefinitionException 存储库进入服务 - Spring NoSuchBeanDefinitionException repository into service Spring Controller,服务中的运行时Java泛型列表 - Runtime Java Generics List in Spring Controller, Services Spring无法自动连接Controller中的存储库 - Spring not able to autowire repository in Controller Spring批注:是否有类似的批注,如@ExceptionHandler应用于@Repository或@Service构造型的Controller构造型中? - Spring annotations: Is there a similar annotation like @ExceptionHandler used in Controller stereotypes for @Repository or @Service stereotypes?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM