Страницы

Поиск по вопросам

Показаны сообщения с ярлыком spring. Показать все сообщения
Показаны сообщения с ярлыком spring. Показать все сообщения

суббота, 11 апреля 2020 г.

Spring RESTful Service

#java #spring #hibernate #rest

                    
Вообщем пишу веб-приложение на Spring. В приложение есть модель:

@Entity
@Table(name = "RSS_STREAM", uniqueConstraints = @UniqueConstraint(columnNames = {"link"}))
public class RssStream implements Serializable{

  @Id
  @GeneratedValue
  @Column
  private int id;

  @Column
  private String title;

  @Column
  @org.hibernate.validator.constraints.URL
  private String link;

  @Column
  @org.hibernate.validator.constraints.URL
  private String image;

  @Column
  private String description;

  @OneToMany(mappedBy = "rssStream", cascade = CascadeType.ALL)
  private Set feeds = new HashSet();
  // Тут еще геттеры и сеттеры, но не привожу их, т.к. они стандартные
}


Другая таблица:

@Entity
@Table(name = "RSS_FEED")
public class RssFeed {

  @Id
  @Column
  private String title;

  @Column
  @URL
  private String link;

  @Column
  private String description;

  @Column
  private String content;

  @Column
  @Temporal(TemporalType.TIMESTAMP)
  private Date pubDate;

  @Column
  @Temporal(TemporalType.TIMESTAMP)
  private Date updateDate;

  @ManyToOne
  @JoinColumn(name = "id")
  private RssStream rssStream;
}


Есть контроллер, который возвращает сериализованный объект RssStream, там есть все
поля. Но одно но, мне не нужно, что бы там было поле feeds. Если убрать геттеры и сеттеры,
то возникают проблемы при выборке из таблици RssFeed, что делать? Возможно ли как-то
исключить поля из сериализатора.
    


Ответы

Ответ 1



Вообщем в Jackson есть специальная аннотация: JsonIgnoreProperties. Она помогла решить проблему.

четверг, 9 апреля 2020 г.

Сквозное логирование при помощи Spring java

#java #spring #aop

                    
Пишу небольшой проектик, будет в итоге типа социальной сети. Сейчас самое начало работы. 

Есть класс Contact, содержащий информацию о человеке. Интерфейс ContactDAO, для работы
с базой данных и тестовая его реализация с мапой ContactSimpleDAO. Сервисная прослойка
интерфейс ContactServise и его реализация ContactManager. 

Весь проект есть на Github 
Попыталась допилить логгер. Проставила аннотацию @AutoLogging над классами, методы
которых нужно логировать и написала соответствующий BeanPostProcessor:

public class AutoLoggingBeanPostProcessor implements BeanPostProcessor {

    Map classMap = new HashMap<>();
    private AutoLoggingController loggingController = new AutoLoggingController();
    final Logger logger = LoggerFactory.getLogger(AutoLogging.class);

    public AutoLoggingBeanPostProcessor() throws Exception {
        MBeanServer platformMBeanServer = ManagementFactory.getPlatformMBeanServer();
        platformMBeanServer.registerMBean(loggingController, new ObjectName("autologging",
"name", "autologger"));
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws
BeansException {
        Class beanClass = bean.getClass();
        if (beanClass.isAnnotationPresent(AutoLogging.class)) {
            classMap.put(beanName, beanClass);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws
BeansException {
        Class beanClass = classMap.get(beanName);
        if (beanClass != null) {
            return Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(),
new InvocationHandler() {

                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
                    if (loggingController.isEnabled()) {
                        logger.debug("Call method " + method + " with args: " + Arrays.toString(args));
                        Object result;
                        try {
                            result = method.invoke(bean, args);
                            logger.debug("Method " + method + " returns " + result);
                            return result;
                        } catch (Exception e) {
                            logger.error("Method " + method + "threw Exception ", e);
                            throw e;
                        }
                    } else {
                        return method.invoke(bean, args);
                    }
                }
            });
        }
        return bean;
    }
}


Спринговые конфигурации:

@Configuration
@PropertySource("classpath:ContactBookMaximumSize.properties")
@PropertySource("classpath:contacts.properties")
@ComponentScan(basePackages = {"com.stoxa.springjavaconfig.*"},
    nameGenerator = KsushikBeanNameGenerator.class)
public class AppConfig {
    @Bean
    public ContactBeanFactory contactBeanFactory() {
        return new ContactBeanFactory();
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer configurer() {
    return new PropertySourcesPlaceholderConfigurer();
    }

    @Value("${maxSize}")
    private int maxContactBookSize;

    @Bean
    public ContactDAO dao() throws Exception {
        final ContactSimpleDAO dao = new ContactSimpleDAO();
        Map contacts = new HashMap();
        contacts.put(contactBeanFactory().getObject().getPhone(),contactBeanFactory().getObject());
        contacts.put(contactBeanFactory().getObject().getPhone(),contactBeanFactory().getObject());
        contacts.put(contactBeanFactory().getObject().getPhone(),contactBeanFactory().getObject());
        contacts.put(contactBeanFactory().getObject().getPhone(),contactBeanFactory().getObject());
        contacts.put(contactBeanFactory().getObject().getPhone(),contactBeanFactory().getObject());
        dao.setContacts(contacts);
        return dao;
    }

    @Bean(initMethod = "init")
    public ContactService contactService() throws Exception {
        ContactManager contactService = new ContactManager();
        contactService.setDao(dao());
        contactService.setMaxContactBookSize(maxContactBookSize);
        return contactService;
    }

    @Bean
    public ApplicationEventPublisherAware applicationEventPublisherAware() {
        return new ContactManager();
    }

    @Bean
    ApplicationListener applicationListener() {
        return new DeleteContactListener();
    }

    @Bean
    public AutoLoggingBeanPostProcessor autologgingBeanPostProcessor() throws Exception {
        return new AutoLoggingBeanPostProcessor();
    }
}




При попытке скомпилить получаю ошибку:

Dec 14, 2015 11:40:09 PM org.springframework.context.annotation.AnnotationConfigApplicationContext
prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@37a71e93:
startup date [Mon Dec 14 23:40:09 EET 2015]; root of context hierarchy
Dec 14, 2015 11:40:09 PM org.springframework.context.support.PostProcessorRegistrationDelegate$BeanPostProcessorChecker
postProcessAfterInitialization
INFO: Bean 'appConfig' of type [class com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6]
is not eligible for getting processed by all BeanPostProcessors (for example: not eligible
for auto-proxying)
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Dec 14, 2015 11:40:10 PM org.springframework.context.annotation.AnnotationConfigApplicationContext
refresh
WARNING: Exception encountered during context initialization - cancelling refresh attempt
org.springframework.beans.factory.BeanCreationException: Error creating bean with
name 'contactService' defined in com.stoxa.springjavaconfig.Config.AppConfig: Bean
instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.Service.ContactService]: Factory
method 'contactService' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dao' defined in com.stoxa.springjavaconfig.Config.AppConfig:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao'
threw exception; nested exception is java.lang.IllegalArgumentException: Cannot subclass
final class class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84)
    at com.stoxa.springjavaconfig.TestClass.TestClass.main(TestClass.java:23)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate
[com.stoxa.springjavaconfig.Service.ContactService]: Factory method 'contactService'
threw exception; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dao' defined in com.stoxa.springjavaconfig.Config.AppConfig:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao'
threw exception; nested exception is java.lang.IllegalArgumentException: Cannot subclass
final class class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 13 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'dao' defined in com.stoxa.springjavaconfig.Config.AppConfig: Bean instantiation
via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao'
threw exception; nested exception is java.lang.IllegalArgumentException: Cannot subclass
final class class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.dao()
    at com.stoxa.springjavaconfig.Config.AppConfig.contactService(AppConfig.java:69)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.CGLIB$contactService$0()
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6$$FastClassBySpringCGLIB$$dd5529ed.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.contactService()
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 14 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate
[com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao' threw exception;
nested exception is java.lang.IllegalArgumentException: Cannot subclass final class
class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 35 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class
com.sun.proxy.$Proxy14
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.enhanceFactoryBean(ConfigurationClassEnhancer.java:402)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:301)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.contactBeanFactory()
    at com.stoxa.springjavaconfig.Config.AppConfig.dao(AppConfig.java:57)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.CGLIB$dao$5()
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6$$FastClassBySpringCGLIB$$dd5529ed.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.dao()
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 36 more

Exception in thread "main" org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'contactService' defined in com.stoxa.springjavaconfig.Config.AppConfig:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.Service.ContactService]: Factory
method 'contactService' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dao' defined in com.stoxa.springjavaconfig.Config.AppConfig:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao'
threw exception; nested exception is java.lang.IllegalArgumentException: Cannot subclass
final class class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:834)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.context.annotation.AnnotationConfigApplicationContext.(AnnotationConfigApplicationContext.java:84)
    at com.stoxa.springjavaconfig.TestClass.TestClass.main(TestClass.java:23)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate
[com.stoxa.springjavaconfig.Service.ContactService]: Factory method 'contactService'
threw exception; nested exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'dao' defined in com.stoxa.springjavaconfig.Config.AppConfig:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao'
threw exception; nested exception is java.lang.IllegalArgumentException: Cannot subclass
final class class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 13 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating
bean with name 'dao' defined in com.stoxa.springjavaconfig.Config.AppConfig: Bean instantiation
via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao'
threw exception; nested exception is java.lang.IllegalArgumentException: Cannot subclass
final class class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:305)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:301)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:196)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.dao()
    at com.stoxa.springjavaconfig.Config.AppConfig.contactService(AppConfig.java:69)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.CGLIB$contactService$0()
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6$$FastClassBySpringCGLIB$$dd5529ed.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.contactService()
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 14 more
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate
[com.stoxa.springjavaconfig.DAO.ContactDAO]: Factory method 'dao' threw exception;
nested exception is java.lang.IllegalArgumentException: Cannot subclass final class
class com.sun.proxy.$Proxy14
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
    ... 35 more
Caused by: java.lang.IllegalArgumentException: Cannot subclass final class class
com.sun.proxy.$Proxy14
    at org.springframework.cglib.proxy.Enhancer.generateClass(Enhancer.java:446)
    at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:25)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:317)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.enhanceFactoryBean(ConfigurationClassEnhancer.java:402)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:301)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.contactBeanFactory()
    at com.stoxa.springjavaconfig.Config.AppConfig.dao(AppConfig.java:57)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.CGLIB$dao$5()
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6$$FastClassBySpringCGLIB$$dd5529ed.invoke()
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
    at com.stoxa.springjavaconfig.Config.AppConfig$$EnhancerBySpringCGLIB$$ade870a6.dao()
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
    ... 36 more


Пожалуйста, помогите разобраться.
    


Ответы

Ответ 1



В общем, ваша проблема в том, что вы вызываете метод contactBeanFactory внутри @Bean-метода dao(). Или в том, что вы подменяете ContactBeanFactory на прокси в своем AutoLoggingBeanPostProcessor, на выбор. Уберите аннотацию с ContactBeanFactory и вылетать перестанет. Как сделать сквозное логирование в FactoryBean'е с вашей конфигурацией - не знаю, я эту маску на стройке нашел. Судя по SPR-6602, когда делали @Configuration, столкнулись с тем, что getSomethingFactoryBean().getObject() возвращает каждый раз разные объекты, что не совпадало с поведением xml-конфигурации. Поэтому придумали при вызове @Bean-метода, возвращающего FactoryBean проксировать результат, чтобы его getObject() возвращал кэшированый бин. Поскольку вы уже создали прокси, который является final-подклассом, сделать еще один подкласс нельзя, и все падает.

Ответ 2



Обратите внимание на вашу конфигурацию: при создании бина ContactDAO, вам требуется бин ContactBeanFactory. Вы пытаетесь получить его, вызвав метод contactBeanFactory(). В данном случае, при вызове метода contactBeanFactory(), вы не получите проинициализированный бин из контекста спринга, а будете получать новый объект на каждый вызов метода. Вероятно, следующие поправки в конфигурации решат вашу проблему: @Bean public ContactDAO dao(ContactBeanFactory contactBeanfactory) throws Exception { final ContactSimpleDAO dao = new ContactSimpleDAO(); Map contacts = new HashMap(); contacts.put(contactBeanFactory.getObject().getPhone(),contactBeanFactory.getObject()); contacts.put(contactBeanFactory.getObject().getPhone(),contactBeanFactory.getObject()); contacts.put(contactBeanFactory.getObject().getPhone(),contactBeanFactory.getObject()); contacts.put(contactBeanFactory.getObject().getPhone(),contactBeanFactory.getObject()); contacts.put(contactBeanFactory.getObject().getPhone(),contactBeanFactory.getObject()); dao.setContacts(contacts); return dao; } @Bean(initMethod = "init") public ContactService contactService(ContactDAO contactDAO) throws Exception { ContactManager contactService = new ContactManager(); contactService.setDao(contactDAO); contactService.setMaxContactBookSize(maxContactBookSize); return contactService; }

Публикация MVC-приложения на сервер

#java #angularjs #spring #cloud

                    
В качестве курсовой писал MVC веб-приложение (связка ангуляра и спринга). Теперь
задача стоит организовать виртуальный хостинг где-нибудь в облаке, чтобы приложение
испробовать не только на локальной машине. 

Как все это грамотно сделать?
    


Ответы

Ответ 1



Самый легкий способ developers.openshift.com : Зарегистрируйтесь на RedHat. Скачайте Jboss dev studio закиньте туда проект. Нажимаете правой кнопкой на проект и выбираете publish, вместо локального сервера в нем выбираете openshift(понадобиться вбить логин и пароль), дальше студия сама зальет на сервер проект, без танцев с бубном. Домен будет выглядеть так: "название проекта" - "Ваш ник".rhcloud.com На openshift можете разместить бесплатно 3 проекта. Из DB можно подключить: MongoDB, MySql, PostgreSql. Потруднее - бесплатный хостинг на heroku.com там танцы с бубном через git но благо есть пошаговая инструкция Вариант есть еще гугловская платформа console.developers.google.com, но ничего не могу сказать о ней так как не пробовал сам, но она тоже богата туториалами

четверг, 2 апреля 2020 г.

Как обновить autowired коллекцию Spring

#java #spring

                    
Имеется коллекция объектов

@Autowired
private List objects;


В рантайме создаю новую реализацию интерфейса SomeInterface, 
Как сделать , чтобы спринг обновил эту коллекцию? 
    


Ответы

Ответ 1



Можете сделать так: @Autowired private ApplicationContext context; public Collection getList(){ return context.getBeansOfType(SomeInterface.class); } Но, чтобы это правильно работало, необходимо вашу новую реализацию зарегистрировать в контексте spring'a . Например так: ((DefaultListableBeanFactory)context .getAutowiredCapableBeanFactory()) .registerSingleton(new SomeInterfaceImpl());

Spring Security: как сделать разделение ролей?

#java #spring #spring_mvc #spring_security

                    
Как в Spring сделать разделение ролей? Если, например, стоит, что администратор (значение
из базы) true, то открыта конкретная ссылка для просмотра в jsp и на эту страницу (на
которую вела ссылка) вход закрыт прочим пользователям (с другими ролями).

Это делается через Spring Security, верно?

UPD: Буду рад любым советам. Кто-то поставил минус, просьба отписаться в комментариях.
    


Ответы

Ответ 1



Как-то так, например some_page.jsp Админка SomeController.java @Controller public class SomeController { @RequestMapping(path = "/admin", method = RequestMethod.GET) @PreAuthorize("hasRole('ROLE_ADMIN')") public String admin(Model model) { return "admin"; } } Совет простой - попробуйте почитать документацию, там всё очень подробно описано.

вторник, 31 марта 2020 г.

BackUp БД postgresql через pg_dump не работает при вызове команды из Spring

#java #база_данных #postgresql #spring #kotlin


Дано:

БД postgresql на Mac. В ней есть данные и я могу сделать BackUp из консоли вызвав
/Library/PostgreSQL/10/bin/pg_dump -U db_user_name -w -c -f my_db_name.sql my_db_name,
что создаст файл my_db_name.sql в папке где я вызываю команду.

Задача:

Настроить периодический BackUp БД через Spring.

Проблема:

При вызове вышеуказанного скрипта программно получаю ошибку Файл не найден

Вопрос:

Как же это реализовать? Кажется, проблема в правах доступа к файлам/папкам, но непонятно
какая именно и как узнать конкретно.

Пробовал:

Пробовал указывать абсолютный путь типа {ПУТЬ_К_ПРОЕКТУ_СПРИНГА}/my_db_name.sql или
/Users/myusername/my_db_name.sql - не помогает.

Код:

@Scheduled(cron = "0 * * * * *")
fun backUpDb() {
    val executeCmd = "/Library/PostgreSQL/10/bin/pg_dump -U $dbUserName -w -c -f
$database.sql $database"

    val runtimeProcess: Process
    try {
        val pb = ProcessBuilder(executeCmd)
        pb.redirectOutput(Redirect.INHERIT)
        pb.redirectError(Redirect.INHERIT)
        runtimeProcess = pb.start()
        val processComplete = runtimeProcess.waitFor()

        if (processComplete == 0) {
            println("Backup created successfully")
        } else {
            println("Could not create the backup")
        }
    } catch (ex: Exception) {
        ex.printStackTrace()
    }
}


Лог:

java.io.IOException: Cannot run program "/Library/PostgreSQL/10/bin/pg_dump -U db_user_name
-w -c -f my_db_name.sql my_db_name": error=2, No such file or directory
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
    at ru.scp.quiz.service.quiz.QuizServiceImpl.backUpDb(QuizServiceImpl.kt:75)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
    at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.io.IOException: error=2, No such file or directory
    at java.lang.UNIXProcess.forkAndExec(Native Method)
    at java.lang.UNIXProcess.(UNIXProcess.java:247)
    at java.lang.ProcessImpl.start(ProcessImpl.java:134)
    at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)

    


Ответы

Ответ 1



Проблема оказалась в том, что команда в одной строке не распознаётся и надо составлять массив из каждой её части и тогда оно работает. Т.е. надо команду в массив превратить при передаче ProcessBuilder-у: val pb = ProcessBuilder(executeCmd.split(" "))

Spring как сделать один контроллер для всех страниц не перекрывая static?

#spring #spring_boot


Собственно есть конфигурация вида:

http.authorizeRequests()
        .antMatchers("/css/**").permitAll()
        .antMatchers("/js/**").permitAll()
        .antMatchers("/images/**").permitAll()
        .antMatchers("/extjs/**").permitAll()
        .antMatchers("/login/restore").anonymous()
        .antMatchers("/login/reg").anonymous()
        .antMatchers("/login/auth").anonymous()
        .anyRequest().authenticated()


И есть контроллер:

@Controller
@RequestMapping("/**")
public class Index {
    @GetMapping
    public String get() {
        return "index";
    }
}


Сейчас получается так, что из-за роутинга @RequestMapping("/**") перекрывается роутинг
для static файлов. Как этого избежать?
    


Ответы

Ответ 1



Добавьте в конфигурацию следующее: @Override public void configure(WebSecurity web) { web.ignoring().antMatchers("/js/**", "/css/**", "/images/**", "/extjs/**"); } А вот эту часть можно убрать : .antMatchers("/css/**").permitAll() .antMatchers("/js/**").permitAll() .antMatchers("/images/**").permitAll() .antMatchers("/extjs/**").permitAll()

Ответ 2



Вариант 1. Разместить все ресурсы в подпапках и добавить ResourceHandler с высоким приоритетом: @Configuration public class ResourceConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.setOrder(Ordered.HIGHEST_PRECEDENCE); registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/"); registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/"); registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/"); } } Вариант 2. Вручную проверить существование ресурса. (Не знаю как это скажется на производительности) @Controller public class IndexController { @GetMapping("/**") @ResponseBody public Object get(HttpServletRequest request) { ClassPathResource resource = new ClassPathResource("/static" + request.getRequestURI()); if (resource.exists()) { return resource; } return new ModelAndView("index"); } } Вариант 3. Если вы делаете одностраничное приложение, то, возможно, будет проще перечислить все возможные пути: @Controller public class IndexController { @GetMapping({"/page1/**", "/page2/**", "/page3/**"}) public String get() { return "index"; } }

Ответ 3



Не понятен смысл данного решения. Но все же, если Вы хотите конкретно рисовать компоненты в самой вьюхе и передавать в аргументы блоки (соответственно на фронте уже парсить их), то скудное решение в виде абстракции/наследования и возврат для любого реквеста в функцию commonPage Имхо public abstract class AbstractController { public String commonPage(ModelMap map) { map.addAttribute("commonObject", new Object()); ..... map.addAttribute("page", "/templates/someHtmlOrJsp.html|.jsp"); ..... return "index"; } } SampleController @Controller @RequestMapping("/") public class SampleController extends AbstractController { @RequestMapping(method = {GET, HEAD}) public String index(ModelMap map) { map.addAttribute("somePageObject", new Object()); .... return commonPage(map); } }

понедельник, 30 марта 2020 г.

Неявное поведение spring при работе с дженериками

#java #spring #docker #spring_boot


Есть некая сущность Report и одна из ее реализаций:

public class CCReport extends AbstractReport {

    public CCReport(List rows, LocalDate from, LocalDate to) {
        super(rows, from, to);
    }

    @Override
    public Class getRowClass() {
        return CCReportRow.class;
    }
}


Есть некий интерфейс сервиса: 

public interface ReportService {
    T createReport(LocalDate from, LocalDate to);
}


У него есть несколько реализаций в зависимости от типа Report:

@Service
@RequiredArgsConstructor
public class CCReportService implements ReportService {

    private final CCReportsExportRepository repository;

    @Override
    public CCReport createReport(LocalDate from, LocalDate to) {
        return repository.generateReport(from, to);
    }
}


Далее есть абстрактная реализация слушателя RabbitMq:

@Slf4j
@RequiredArgsConstructor
public abstract class AbstractReportTaskListener implements ReportTaskListener {

    protected final ReportService reportService;
    //-------------------//    

    @Override
    public void processReportTask(SingleReportRequest reportRequest) {
        Report report = reportService.createReport(reportRequest.getFrom(), reportRequest.getTo());
        //-------------------//
    }
}


И непосредственно сама реализация этого слушателя:

@Component
public class RabbitCCReportTaskListener extends AbstractReportTaskListener {

    public RabbitCCReportTaskListener(
            ReportService reportService,
            ReportMailService mailService,
            ReportToExcelService excelService,
            ReportsNameGenerator nameGenerator,
            WebDavStorageService webDavStorageService) {
        super(reportService, mailService, excelService, nameGenerator, webDavStorageService);
    }

    @RabbitListener(queues = RabbitConfig.CC_QUEUE, concurrency = "2-2", autoStartup
= "true")
    @Override
    public void processReportTask(SingleReportRequest reportRequest) {
        super.processReportTask(reportRequest);
    }
}


При запуске всего этого добра через gradle bootRun все запускается без проблем, однако,
если создаю docker-образ вылетает ошибка:


  *********************** APPLICATION FAILED TO START
  
  
  
  Description:
  
  Parameter 0 of constructor in
  com.reports.service.RabbitCCReportTaskListener required a single bean,
  but 2 were found:
   - CCReportService: defined in URL [jar:file:/app/reports.jar!/BOOT-INF/classes!/reports/service/CCReportService.class]
   - SRReportService: defined in URL [jar:file:/app/reports.jar!/BOOT-INF/classes!/reports/service/SRReportService.class]
  
  Action:
  
  Consider marking one of the beans as @Primary, updating the consumer
  to accept multiple beans, or using @Qualifier to identify the bean
  that should be consumed


В конце концов приходится явно описывать бины через @Qualifier и тогда начинает работать.
Подскажите, с чем может быть связано такое поведение?

UPD:
Вот ссылка на SO, где уже описывали подобный вопрос. Плюс есть несколько статей по
запросу "spring generic bean autowire"
    


Ответы

Ответ 1



Это случается из-за Type Erasure: при компиляции ReportService вырождается в ReportService, и здесь возникает неоднозначность в рантайме, т.к. таких бинов уже 2. Чтобы избежать ситуации используйте либо конкретный наследник ReportService либо @Qualifier в конструкторе конкретного наследника AbstractReportTaskListener. В докер упакованы все jar-файлы проекта и все зависимости. Локально, вероятно, не все скомпилировано, попробуйте пересобрать проект начисто.

Как правильно использовать мавен-профили при сборке war?

#java #spring #maven #tomcat #profile


Я использую Spring + Maven + Tomcat.
Общая задача - настроить работу с профилями. 
В моем понимании, один из способов, это использовать Maven, для него в pom.xml указать
профили и запускать их использую -P {имя профиля}.

Так же я создал application.properties с свойствами и его дублер по имени application-dev.properties.
В application.properties так же добавил строку 
spring.profiles.active=${spring.profiles.active}.

Я ожидаю, что в процессе сборки mvn clean package -P dev в результирующем war в файле
application.properties все значения свойств перезапишуться из application-dev.properties,
но этого не происходит, что я делаю неправильно?

pom.xml:


    
        dev
        
            
                spring.profiles.active
            
        
    
    
        at1
        
            
                spring.profiles.active
            
        
    


    


Ответы

Ответ 1



Профайлы Spring можно активировать с помощью профайлов Maven, указав свойство spring.profiles.active. В каждом профайле Maven можно установить это свойство: dev dev at1 at1 Его значение будет использоваться для замены @spring.profiles.active@ шаблона в application.properties: spring.profiles.active = @spring.profiles.active@ Файлы свойств также будут использоваться, специфичные для профайла. Они должны иметь имя в формате application-{profile}.properties. Cвойства в файле application.properties автоматически загружаются для всех профайлов, а те, которые содержатся в файлах application-{profile}.properties только для определенного профайла. И вы правильно подметили для активации профайла можно использовать параметр -P в Maven.

воскресенье, 29 марта 2020 г.

Преобразовать данные из MongoDB

#java #spring #mongodb #spring_boot


Есть класс Person, в нем есть поле name. Я записываю эти данные в Mongo, но на выходе,
хочу получать не записанные по 1-у классы, а все поля name из них, но в List.
Вот код 

@RestController
public class Post_Get {
    @Autowired
    private PersonRepository personRepository;
    private List persons = new ArrayList<>();

    @PostMapping("api/names")
    public void post (@RequestParam("username") String name) {
        Person person = new Person(name);
        personRepository.save(person);
    }

    @GetMapping("api/names")
    public List get () {
        return personRepository.findAll();
    }
}

    


Ответы

Ответ 1



@GetMapping("api/names") public List getNames() { return personRepository.findAll() .stream() .map(Person::getName) .filter(Objects::nonNull) .collect(Collectors.toList()); } Или без лишней конвертаций public interface PersonRepository extends Repository { Stream findByNameNotNull(); } @GetMapping("api/names") public List getNames() { return personRepository.findByNameNotNull() .map(Person::getName) .collect(Collectors.toList()); }

пятница, 13 марта 2020 г.

Как организовать разработку приложения

#java #spring #hibernate #maven #веб_программирование


Здравствуйте!

Подскажите, пожалуйста, как организовать разработку веб-приложения, а именно, как
организовать взаимосвязь между применяемыми технологиями.

Я хочу создать веб-приложение по обмену вещами между пользователями. Приложение пишется
на Java + Spring MVC + Spring Security (для авторизации пользователя) + Hibernate с
использованием сборщика Maven, а в качестве СУБД используется HSQLDB. Для Представления
используется JSP. Сервер приложений - встроенный Jetty, не требующий внешнего веб-контейнера.

Вопросы:


Как сделать так, чтобы проект автоматически собирался и работал на любом ПК с предустановленными
JDK и Maven? Что для этого нужно сделать?
Что сделать, чтобы нужная схема данных автоматически создавалась и заполнялась начальными
данными при первом запуске веб-приложения?
Это должно происходить именно при первом запуске приложения, а не при каждом его
включении.
Расскажите поподробнее про то, как мне организовать доступ к HSQLDB из Hibernate,
учитывая требования (1 и 2) и как хранить/упаковать БД и СУБД исходя из этого.
Требуется также написать скрипт сборки проекта с помощью Maven и показать его исходники
заказчику. Что в данной ситуации будет скриптом сборки? Maven ведь декларативный сборщик.


Спасибо заранее!
    


Ответы

Ответ 1



Для этого достаточно использовать maven в качестве билд-системы. Тогда на любой машине с установленными maven и jdk можно будет выполнить mvn package и получить артефакт (вероятнее всего вы захотите zip-архив) с вашим продуктом. Вам скорее всего понадобятся maven-shade-plugin и/или maven-assembly-plugin. Автоматическое создание схемы можно доверить Hibernate (используя параметр hibernate.hbm2ddl.auto=update), но предпочтительнее делать это SQL-скриптом. Если планируются апдейты приложения и схемы данных, стоит задуматься об использовании средств версионирования схемы БД. Например, Flyway умеет проверять при старте версию схемы в БД последовательно накатывать необходимые миграции (SQL-скрипты, обновляющие схему) на БД и заливать исходные данные из XML. Файл данных БД можно хранить в директории приложения или за её пределами, например, в $HOME/.myapplication/ или в /var в Linux (%APPDATA%/myapplication в случае Windows). Хранение базы данных в отдельной рабочей директории даст ей больше шансов на выживание при удалении и переустановке вашей программы. Мавеновский pom.xml и будет скриптом сборки. Декларативным скриптом. Примерно все это можно получить "из коробки", используя Spring Boot. Просто идете на страницу http://start.spring.io, жмете Switch to the full version? заполняете форму и отмечаете флажками пункты: Web Security JPA HSQLDB и Generate project в конце. На выходе у вас будет архив с готовым скелетом приложения c maven-скриптом как раз под ваши нужды. Нужно будет доработать напильником: заменить Tomcat на Jetty и досыпать в зависимости Flyway, например.

воскресенье, 8 марта 2020 г.

Для чего используется Spring Boot

#java #spring #spring_boot


Объясните в каких случаях целесообразно использовать Spring Boot framework в дополнении
к Spring?

И какие его основные features?
    


Ответы

Ответ 1



Spring Boot сделан для того, чтобы у разработчика было больше свободного времни, которое он бы мог посвятить просматриванию демотиваторов вместо тупой и рутинной работы, вроде поиска проблем в pom файле и xml-конфигураций. :-)

Ответ 2



Ответ выше не является плохим. Spring Boot просто позволяет с минимальными настройками сделать готовый проект на фреймворке Spring.

среда, 4 марта 2020 г.

Разница между bean scope Singleton и Global-session?

#java #spring


Пытаюсь понять разницу между областями бинов Singleton и Global-session. 

Если мы делаем Singleton то контекст возвращает один и тот же бин.

final ClassPathXmlApplicationContext context =
            new ClassPathXmlApplicationContext("spring-context.xml");


При вызове context.getBean(SomeClass.class) будет возвращаться один и тот же объект
если scope=singleton или ничего, но если мы укажем scope=globalSession, то результат
будет тот-же. 

Но есть же неявная разница...

А в чем? Как ее увидеть? И для чего это может помочь? Спасибо.
    


Ответы

Ответ 1



Из документации Spring : singleton (Default) Scopes a single bean definition to a single object instance per Spring IoC container. session Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext. globalSession Scopes a single bean definition to the lifecycle of a global HTTP Session. Typically only valid when used in a Portlet context. Only valid in the context of a web-aware Spring ApplicationContext. singleton-бин имеет один экземпляр в пределах всего IoC-контейнера session-бин имеет один экземпляр в пределах HTTP-сессии и умирает вместе с ней: When the HTTP Session is eventually discarded, the bean that is scoped to that particular HTTP Session is also discarded. globalSession-бин почти аналогичен session - он используется в портлетных веб приложениях. Когда вы используется globalSession-бин в "стандартном" сервлетном приложении эти бины имеют session-scope: If you write a standard Servlet-based web application and you define one or more beans as having globalSession scope, the standard HTTP Session scope is used, and no error is raised Но есть же неявная разница... А в чем? Как ее увидеть? Чтобы увидеть, что session-бин имеет разные экземпляры в разных сессиях (в "стандартном" spring веб-приложении), вы, например, можете обратиться к одному и тому же методу контроллера, в котором есть этот бин, из 2 окон браузера (одно в обычном режиме, другое в инкогнито). Пример из приложения под рукой: r.p.f.r.service.BlankServiceImpl@6f7b9a10 (1ое окно - http-сессия 1) r.p.f.r.service.BlankServiceImpl@18d5bfc0 (2ое окно - http-сессия 2) При повторных запросах используются все те же экземпляры (т.к. http-сессии все еще живые). Если scope бина singleton, то экземпляр всегда один и тот же: r.p.f.r.service.BlankServiceImpl@1fec9d33 (1ое окно - http-сессия 1) r.p.f.r.service.BlankServiceImpl@1fec9d33 (2ое окно - http-сессия 2)

Как настроить HTTPS в Spring

#java #spring #https


есть готовое приложение на Spring. Пытаюсь сделать так, чтобы все запросы к серверу
передавались через HTTPS. Потратив несколько часов на гугление, сделал вот что. 
 1. Создал файл contactmanager.keystore вызвав команду в терминале (CMD) 

keytool -genkey -alias ContactManager -keyalg RSA -keystore c:/contactmanager.keystore



В файле C:\Program Files\Apache Software Foundation\Tomcat 9.0_MyTomcat9\conf\server.xml
добавил следующее:
св  

< Connector port="8443" 
    SSLEnabled="true" 
    protocol="org.apache.coyote.http11.Http11NioProtocol"
    maxThreads="150" scheme="https" secure="true"
    keystoreFile="c:\contactmanager.keystore"
    keystorePass="transmitter"
    sslProtocol="TLS"/>
В файле security-config.xml (в самом проекте) написано так:


















Запускаю томкат, все деплоится, запускается. Но для меня остается загадкой, почему
нету значка "Зеленый замочек" рядом слева от адресной строки? Такой, как например,
на этой странице. И потом, говорят, что этот протокол шифрует все данные и подсмотреть
их нельзя. Но как так получается, что все get/post запросы я вижу в их "голом" виде???

Я новичок в HTTPS, многого не знаю. Вроде делал все по туториалам, но эффект не такой
какой я ожидал. 
    


Ответы

Ответ 1



эффект не такой какой я ожидал Эффект именно такой, какой и должен быть. Ваше спринг-приложение и сервлет-контейнер теперь работают с https, с чем Вас можно поздравить. почему нету значка "Зеленый замочек" Этот значок означает, что сервер является именно тем, за кого себя выдаёт. Для этого сервер должен использовать сертификат, выданный удостоверяющим центром. У вас же сертификат самоподписанный (Вы его сами сгенерировали), и доверия к нему у браузера нет. Кроме того, сервер у вас работает на localhost, и удостоверять соответствие сертификата доменному имени тут смысла нет. Поэтому нет и замочка. как так получается, что все get/post запросы я вижу в их "голом" виде Вы смотрите на на них через консоль разработчика в браузере. Браузер всё расшифровывает специально для вас. Попробуйте запустить перехватчик пакетов, посмотреть, что передается в реальности, и убедитесь, что ваши данные надежно зашифрованы.

суббота, 29 февраля 2020 г.

Нужно ли в REST API выносить названия методов в отдельный файл с настройками?

#java #spring #rest


Пишу rest api на spring. Контроллеры оборачиваю в @RequestMapping, а имена методов
захардкодены. Например @RequestMapping("register"). Стоит ли их выносить в *.properties
файл или есть более "спринговый" способ? Понимаю, что вопрос может показаться довольно
глупым, просто хочу услышать мнение посторонних.
    


Ответы

Ответ 1



Можно создать такой класс: public final class BaseApi { public static final String REGISTER = "/register"; public static final String LOGIN = "/login"; public static final String LOGOUT = "/logout"; private BaseApi() { //prevents instantiation } } И потом при создании контроллера использовать статические импорты. Это нужно для того, чтобы ваши тесты и контроллеры использовали одинаковые константы. Если вы их захардкодите, то при изменении урл, вам понадобится менять и во всех остальных классах, а с таким подходом - только в одном классе.

пятница, 28 февраля 2020 г.

Можно ли над методом рест-контроллера ставить аннотацию @Transactional?

#java #spring #транзакции #jta


Можно ли над методом рест-контроллера ставить аннотацию @Transactional?
Будут ли проблемы, если одновременно по этому URL одновременно будут пытаться получить
данные несколько клиентов?
    


Ответы

Ответ 1



Нельзя, однозначно и бесповоротно. Будут проблемы связанные с обработкой транзакций. Здесь я укажу некоторые ссылки: Слой использования @Transactional анотации.. Что лучше всего с @Transactional, вы должны положить его, если у вас есть доступ к базе данных. См. «Понимание реализации декларативной транзакции Spring Framework» вы просто аннотируете свои классы аннотацией @Transactional, добавляете в свою конфигурацию строку (``), а затем ожидаете, что вы поймете, как все это работает. Какой слой использовать для транзакций и сессии Hibernate. Лучше всего использовать управление транзакциями Spring. Аннотации @Transactional для использования транзакций. На заводе-изготовителе используется LocalSessionFactoryBean. Все бобы управляются весной, поэтому у вас нет забот. Spring Hibernate - различие между CrudRepository и SessionFactory. Просто вы можете найти описание этих аннотаций на сайте docs Spring. В ближайшее время, чтобы ответить на ваши вопросы, разница между ними заключается в том, что они используются для разных целей. @Transactional используется для демаркации кода, участвующего в транзакции. Он помещается на классы и методы. @Repository используется для определения Spring-компонента, поддерживающего транзакции, его также можно использовать в DI. Они могут использоваться как в одном классе.

Ответ 2



Можно. Никаких технических ограничений для этого нет. Но не нужно, так как это неправильно с точки зрения проектирования архитектуры. Ни контроллеры, ни слой доступа к данным не могут располагать необходимыми знаниями о взаимосвязях данных, в контексте которых имеет смысл транзакции применять. Это прерогатива сервисного слоя, в котором и должна располагаться вся бизнес-логика. UPDATE: Так как правильность моего ответа ставят под сомнение, придётся его дополнить. Во-первых, мне приходилось видеть проекты крупных и солидных компаний, в которых на протяжении многих лет транзакции успешно используется именно в web-слое. Во-вторых, первая же ссылка в Google по запросу "spring @transactional @controller" ведёт на большой SO, где люди делятся тем же опытом. Наконец, не может быть более железного аргумента, чем рабочий код. Поэтому я накидал простенький проект и залил его на GitHub - https://github.com/TheDeadOne/spring-transactional-controller-demo.

Ответ 3



Можно Пост процессор, увидев аннотацию @Transactional вокруг аннотированного класса создаст прокси, в котором будут происходить (очень примерно) две вещи Выполняться beginTransaction() перед аннотированным методом (или перед каждым публичным методом аннотированного класса) Выполняться .getTransaction().commit() после аннотированного метода (или после каждого публичного метода аннотированного класса) С точки зрения многопоточности от заворачивания контроллера в прокси ничего не меняется. Но не нужно А вот с точки зрения архитектуры это плохая идея. Первая буква в слове SOLID: The Single Responsibility Principle Ответственность контроллера - получить request и попросить кого нибудь его обработать и отправить ответ. Не надо вешать на него дополнительную функциональность.

четверг, 27 февраля 2020 г.

@value( ${} ) в spring не работает

#java #xml #spring


Пишу приложение на java с использованием Spring. Нужно передать значение ключа из
файла app.properties в поле класса. Передает null. Выскакивает NullPointerException,
уже не знаю что и делать, помогите кто чем может

конфигурация spring:






    



файл properties:

price=^[1-9][0-9.]{0,10}


в классе:

import org.springframework.beans.factory.annotation.Value;
....
@Value("${price}")
private String price;
private Pattern PRICE_REGEX = Pattern.compile(price);

    


Ответы

Ответ 1



@Value("${price}") в твоём случае работает. Другое дело, что ты вызываешь private Pattern PRICE_REGEX = Pattern.compile(price); до того, как отработает @Value. Тебе надо перенести логику инициализации PRICE_REGEX в post-конструктор. На выходе должно получиться примерно так: import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.regex.Pattern; @Component public class Question909652 implements InitializingBean { @Value("${price}") private String price; private Pattern PRICE_REGEX; @Override public void afterPropertiesSet() throws Exception { PRICE_REGEX = Pattern.compile(price); } } Ну или можно похитрить и использовать всю мощь SpEL import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.regex.Pattern; @Component public class Question909652 { @Value("#{T(java.util.regex.Pattern).compile('${price}')}") private Pattern PRICE_REGEX; } P.S. Как правильно заметил @Qwertiy, у тебя очень странное регулярное выражение для цены, быть может тебе больше подойдёт [0-9]*([.][0-9]{1,2})?

Ответ 2



Добавь аннотацию @PropertySource("classpath:app.properties").

Как обернуть вызов сервисов из рест-контроллера для отлова исключений?

#java #spring #jpa


Есть рест - сервис на spring:

@RestController
public class UserController {
    @Autowired
    private UserService service;

    @RequestMapping(value = "/users", method = RequestMethod.POST)
    public Users add(@RequestBody Users users,
                              @RequestParam(value = "id", required = false) String id) {
        return service.add(id, users.getUsers());
    }

    @RequestMapping(value = "/users/{id}", method = RequestMethod.GET)
    public @ResponseBody Users findById(@PathVariable(value = "id") String id) throws
Exception {
        return service.find(id);
    }
}


Который обменивается с клиентом с использованием xml и jaxb. При этом сущность Users
выглядит следующим образом:

@XmlRootElement(name = "Users")
@NoArgsConstructor
@AllArgsConstructor
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
@Setter
public class Users {
    @XmlElement(name = "users")
    private List Users;

    @XmlElement(name="UserError")
    private UserError error;

    public void appendUsers(Users Users){
        if (Users == null) return;

        if (Users.getError() != null){
            this.error = Users.getError();
        }

        if ( Users.getUsers() != null) {
            if (this.Users == null){
                this.Users = new ArrayList<>();
            }
            this.Users.addAll(Users.getUsers());
        }
    }
}


То есть, по сути, это два поля, в одном из котором хранится список пользователей,
в другом - ошибка если возникла.

В процессе выполнения service.add может возникнуть ошибка, например база данных оказалась
недоступна, и метод вернет exception.
Решением в лоб является обертка всех вызовов сервисов в try catch и, если возникло
исключение, запись этой ошибки в Users.error.

Есть ли более элегантное решение?
    


Ответы

Ответ 1



Конечно есть. Для того чтобы отловить ошибку, допустим, UserNotFoundException в UserController необходимо добавить метод с аннотацией @ExceptionHandler: @ExceptionHadler(UserNotFoundException.class) @ResponseStatus(HttpStatus.NOT_FOUND) @ResponseBody private String handleUserNotFoundException( UserNotFoundException ex) { return "user not found"; } Для того чтобы отловить ошибку, допустим, IllegalArgumentException изо всех RestController-ов необходимо обьявить класс с аннотацией @ControllerAdvice: @ControllerAdvice public class RestExceptionHandler { @ExceptionHandler(IllegalArgumentException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody public String handleIllegalArgumentException(...) {...} }

среда, 26 февраля 2020 г.

Как принять и прочитать массив строк при помощи Spring 3?

#spring #json #java


Здравствуйте. Как принять и прочитать массив строк при помощи Spring 3? В качестве
JSON-запроса выступает массив строк. Выглядит он так:

["cnh","dfd","asd"]

Вот то, что принимает на сервере:
@RequestMapping(value = "/deleteelements.form")
@ResponseBody
public String deleteElements(/* ??? */) {
}
    


Ответы

Ответ 1



Попробуйте @RequestMapping(value = "/deleteelements.form") @ResponseBody public String deleteElements(@RequestBody String elements[]) { } Разумеется, для этого Spring должен видеть библиотеку Jackson. В случае с мавеном добавьте зависимости: org.codehaus.jackson jackson-core-lgpl 1.8.4 org.codehaus.jackson jackson-mapper-lgpl 1.8.4 commons-collections commons-collections 3.2.1 Или просто киньте соответствующие jar-ники в WEB-INF/lib. Кроме того, у входящего HTTP-запроса заголовок Content-type должен соответствовать application/json.

Ответ 2



UPD На самом деле интеграция с Jackson реализована в Spring (MappingJacksonHttpMessageConverter), достаточно только подключить его библиотеки, см. ответ @Nofate. Для того, чтобы заработал вариант @Nofate, необходимо сначала добавить конвертер, так как в Спринге нет конвертера для массивов строк. На SO показывается, как это можно сделать (кофигурирование вроде бы должно быть упрощено в Spring 3.1M1): вкратце это просто реализация интерфейса/абстрактного класса конвертера и его регистрация. В самом конвертере можно использовать, к примеру, Jackson, для преобразования. Если это только один раз нужно, то можно сделать и напрямую: @RequestMapping(value = "/deleteelements.form") @ResponseBody public String deleteElements(@RequestBody byte[] data) { // делает то же самое, что делали бы конвертере, // скармливаем Jackson'у байтовый массив }

вторник, 25 февраля 2020 г.

Пример java ee

#java_ee #java #база_данных #spring


Добрый день. Сейчас изучаю стек java технологий связанных с веб разработкой. Ищу
пример проекта с использованием Spring, работой с БД, JSP и прочее сопутствующее с
целью поразбираться в более-мение реальном коде. Подойдет например какой нибудь сайт
с регистрацией, и данными привязанными к аккаунту с JSP фронтом.    


Ответы

Ответ 1



Вот вам рабочий проект. Полноценный форум с пользователями, регистрациями, админками, кэшами и прочим.

Ответ 2



Вряд ли кто даст рабочий проект, но я рекомендую сделать поиск на Github: "Spring Hibernate". По этому поиску выдает много чего. Вот например этот