Skip to content

Instantly share code, notes, and snippets.

@farukh-dm
Created June 18, 2020 16:13
Show Gist options
  • Select an option

  • Save farukh-dm/4417e8efc9ccff441977b090eb3d522b to your computer and use it in GitHub Desktop.

Select an option

Save farukh-dm/4417e8efc9ccff441977b090eb3d522b to your computer and use it in GitHub Desktop.

Revisions

  1. farukh-dm created this gist Jun 18, 2020.
    757 changes: 757 additions & 0 deletions Spring-info.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,757 @@
    Spring is like a container of beans or factory of beans.
    And you ask the container to give you what you need. Container reads from some configuration setup avaialable for it & returns thw required object.
    BeanFactory will help create new objects by reading some configuration.
    We can use BeanFactory object to create target objects. And as the object is created in Bean Factory, Spring handles the life cycle of the object.

    spring DI
    BeanFactory f = new XmlBF(new FileSystemResouce(spring.xml))
    f.getBean(..)
    ----------------------------------
    BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("C:/workspace/project/spring-demo-1/src/main/resources/spring/spring-config.xml"));
    Burger burger = (Burger) beanFactory.getBean("cheeseBurger");
    burger.prepare();
    ------------------------------------
    ApplicationContext is like a big brother of beanFactory. Event notify, AOP, etc.

    ApplicationContext ac = new ClasspathXmlAppContext(spring.xml)
    ac.getBean()

    <beans>

    <bean id="abd" class="a.b.d" />

    <bean id="xyz" class="a.b.c">

    // /member variable / Property Injection / setter injection using set<PropertyName>() method.
    <property name="variable1" value="abc"/>

    // Constructor injection
    <constructor-args value="test"/>
    <constructor-args value="1"/>

    <constructor-args index="0" value="test"/>
    <constructor-args index="1" value="1"/>

    <constructor-args type="java.lang.string" value="test"/>
    <constructor-args type="int" value="1"/>

    // object injection
    <property name="variable2" ref="abd"/>

    //inner bean
    <property name="innerBean1"/>
    <bean id="inner_abc" class="a.b.z">
    <property name="variable1" value="1"/>
    <property name="variable2" value="2"/>
    </bean>
    </property>

    //idref
    <property name="variable3">
    <idref="someid"> // only takes id & not alias
    </property>

    //list
    <property name="listVariable">
    <list>
    <ref bean="" />
    <ref bean="" />...
    </list>
    </property>

    <property name="listVariable">
    <list>
    <value />
    <value />...
    </list>
    </property>

    </bean>

    // alias
    <alias name="abc" alias-name="abc-alias" />
    ac.getBean(abc-alias)

    --------------
    class B1
    <bean name="b1" class="B">
    <bean name="b2" class="B">


    class A
    private B b1
    private B b2

    <bean name="AA" class="A" autowire=byName>
    </bean>
    member variables with same name as beans defined above, this injected.

    autowire=byType works if their is only one bean define of type.
    autowire=constructor, one bean per type

    default = autowire is off

    ------------------------
    scope:
    singlton(initialized by spring when spring container gets initialized)
    prototype: created when requested(.getBean)
    Web aware context:
    Request: per request
    session: user session
    global: portlets

    <bean name="b1" class="B" scope=prototype">
    ---------------------------
    ApplicationContextAware:
    BeanNameAware - To know name of the bean set in the config.

    class A implements ApplicationContextAware, BeanNameAware

    private ApplicationContext appContext;

    // will be called by spring
    public void setApplicationContext(ApplicationContext context) {
    this.appContext = context
    }

    public void setBeanName(String beanName) {
    print(beanName);
    }
    ------------------------
    Bean Definition inheritance:

    <bean name="b1" class="B">
    <property name="b_1" value="1">
    </bean>

    <bean name="b2" class="B" parent="b1">
    <property name="b_2" value="2"> <!-- Additional Property -->
    </bean>

    <bean name="b3" class="B" parent="b2">
    <property name="b_3" value="3">
    </bean>



    <bean name="b1" class="B" abstract="true">...</bean>

    <bean name="b2" class="B" parent="b1" >...</bean>
    overrides common properties

    abstract="true" => initialization will not happen, its just like a template

    -------------------------------------------------
    callbacks:

    For spring web applicaion, it know when to end the spring container. NO explicit registerShutDownHook is required.
    Butin case of desktop app, it is required.

    AbstractApplicationContext ac = new ClasspathXmlAppContext(spring.xml)
    ac.registerShutDownHook(); //for spring to shupdown itself when program ends.

    class A implements initializingBean, DisposableBean {
    public void afterPropertiesSet() {}
    public void destroy() {}
    }

    <bean name="a" class="A" init-method="init" destroy-method="destroy" />
    class A {
    public void init() {}
    public void destroy() {}
    }

    DEFAULT INIT METHOD:-
    <beans default-init-method="init" default-destroy-method="destroy">
    <bean>..
    ...
    </beans>
    ignores if bean does not define it.
    -----------------------------------------------------

    BeanPostProcessor: classes that informs spring needs to use after initializing bean. Called for all beans.

    class ABC implements BeanPostProcessor {

    public object postProcessAfterInitilization(object bean, string name) {
    return object;
    }

    public object postProcessBeforeInitilization(object bean, string name) {
    return object;
    }

    <bean class=ABC />

    }
    ------------------------------------------------
    BeanFactoryPostProcessor: Some code you want to run when Spring's bean factory itself gets initialized.

    class ABS implements BeanFactoryPostProcessor {

    public void postProcessorBeanFactory( ) {
    return object;
    }

    <bean class=ABC />

    ===========================
    PropertyPlaceHolderConfigurer -> is an example of BeanFactoryPostProcessor
    PropertyPlaceHolderConfigurer: bean factory post processor provided by spring.

    demo.properties
    a.val=1
    b.val=2

    <bean class="org.spring...PropertPlaceHolderConfigurer" >
    <property name="location" value="classpath:demo.properties" />
    </bean>

    <bean ...>
    <property name=a value="${a.val}" />
    <property name=b value="${b.val}" />

    }
    --------------------------------------------

    @Required annotation: It's like a bean post processor that run after beans are initialized to check if required annotations are also initialized.

    class A {

    private B b;

    @Required
    public void setB() {

    }
    ...
    }
    In order to make @required to work, we need to add a PostProcessor bean.
    <bean class="org.springframework.bean.factory.annotation.RequiredAnnotationBeanPostProcessor" /> - This checks for annotations

    If bean is not available, error will be caught up during bean initialization/creation phase itself.
    ------------------------------------------------

    @Autowire annotation: Default is by type, then name

    class A {

    private B b;

    @Autowire
    public void setB() {

    }
    ...
    }
    <bean class="A" id=".." />
    <bean class="org.springframework.bean.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> - This checks for annotations

    =================================
    @Autowire
    @Qualifier("bb")
    public void setB() {..}

    <bean class="B" id="...">
    <qualifier value="bb" />
    </bean>
    <bean class="org.springframework.bean.factory.annotation.AutowiredAnnotationBeanPostProcessor" /> - This checks for annotations

    Instead of adding individual annotations bean we can use: for defining all bean post processor tags

    <context: annotation-config />

    ------------------------------------------------------------------------
    JSR annotation: standard java specification request that defines standard annotation that applies across different frameworks.
    Spring supports some of JSR annotations.

    @Resource(name="bb") // javax.annotation. Looks for a bean named bb and inject that.
    public void setB() {..} // default search by name of the member variable if "name" is not provided.

    @PostConstruct // => initializingBean
    public void initBean() {..}

    @PreDestroy(name="bb") // => DisposableBean
    public void destroyBean() {..}

    -----------------------------------------------------------------------------

    @Component => <bean id=".." class=".." />

    @Component tells spring that a particular class to used as a bean.

    Also, tell spring that there are beans inside code & tell it to look for them using below scan line:
    <context:component-scan base-package="" />

    Stereotypes annotation = @controller, @Service, @Repository
    ------------------------------------------

    MessageSource:

    mymessagefile.properties
    home=Hello
    paramMsg=Test {0} & (1)

    <bean id="messageSource" class="ResourceBundleMessageSource" >
    <property name="basenames
    <list>
    <value>mymessagefile</value>
    </list>
    </property
    </bean>

    context.getMessage("home", null, null, null);
    OR

    @Autowired
    private MessageSource messageSource;

    private setMessageSource() {...}

    this.messageSource.getMessage("home", null, null, null);
    this.messageSource.getMessage("home", new Obhect[] {1, 2}, null, null);

    mymessagefile_EN.properties
    this.messageSource.getMessage("home", null, null, "EN");

    -----------------------------------------------------------
    Events:

    @Component
    class MyEventListener implements ApplicationEventListener {

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
    sysout(event.toString());
    }

    }

    custom event:

    class FoodPreparedEvent extends ApplicationEvent {

    public FoodPreparedEvent(Object source) {
    super(source);
    // TODO Auto-generated constructor stub
    }

    public void toString() {
    sysout("Food Prepared")
    }
    }

    class M implements ApplicationEventPublisherAware {

    private ApplicationEventPublisher publisher;

    somemethod() {
    FoodPreparedEvent event = new FoodPreparedEvent();
    publisher.publishEvent(event)
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
    this.publisher = applicationEventPublisher;

    }

    }

    ----------------
    In Java: run program to with:

    System.setProperty("javax.net.debug", "ssl");

    If you are trying to create an SSL connection to a server that doesn't have an official ssl certificate.
    You can work around this by importing the servers certificate into the java cert store.

    ssh://git@cedt-bitbucketcli.nam.nsroot.net:7999/maphub/main.git
    git clone --depth 1 ssh://git@cedt-bitbucketcli.nam.nsroot.net:7999/maphub/main.git
    ----------------------------

    Spring MVC:
    -----------
    in servlet (controller) -> jsp (view) define url mapping in web.xml
    Similarly, instead of multiple servlets we define one front controller called dispatcher servlet(spring) that will take all requests.

    then in spring we make controller using annotation @Controller.
    controller will return data back to dispatcher & dispatcher will provide data to view & return the response.

    Client request -> Front Controller/Dispatcher Servlet ---> handler mapping: to find controller for URL ---> Controller -> back to Dispatcher Servlet -->
    --> View Resolver to find view -> View -> Form response & send back to dispatcher -> return to client

    How to create web mvc:
    1. add dispatcher in web.xml
    2. create <servlet name>-servlet.xml . dispatcher looks for config file using this naming convention.
    3. Eg: demo-servlet.xml

    <context:property-placeholder location="classpath:applicationContext.properties" /> if any

    <mvc:annotation-driven enable-matrix-variables="true">
    <mvc:message-converters>
    jackson..
    </..>
    </annotation>
    <context:component-scan base-package="com.group.project">

    <bean id="viewResolver"
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <property name="viewClass">
    <value>
    org.springframework.web.servlet.view.tiles3.TilesView
    </value>
    </property>
    </bean>

    <mvc:interceptors>
    <bean
    class="com.group.project.vicdw.common.controller.SessionValidatorInterceptor">
    </bean>

    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

    -----------------
    mvc app using config file:

    MyDemoAppConfig.java

    @Configuration
    @ComponentScan({ "com.demo.app"})
    class MyDemoAppConfig {

    @Bean
    public InternalViewResolver viewResolver()

    //InternalViewResolver vr = new InternalViewResolver();
    InternalResourceViewResolver view = new InternalResourceViewResolver();
    vr.setPrefix("/WEB_INF");
    vr.setSuffix("/.jsp");

    }
    }

    we can also replace web.xml with class
    MyWebDotXmlInitializer.java

    class MyWebDotXmlInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    getRootConfigClasses() {}

    getServletConfigClasses() {
    return new Class[] { MyDemoAppConfig.class };
    }

    getServletMappings() {
    return new String[] { "/" };
    }

    }

    ---------------------
    Spring webmvc config java class

    @Configuration
    @EnableMvc
    @ComponentScan({ "com.demo.app"})
    class MyMvcDemoApp extends WebMvcConfigurerAdapter{

    }

    class MyWebDotXmlInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    getRootConfigClasses() {
    return new Class[] { MyMvcDemoApp.class };
    }

    getServletConfigClasses() { }

    getServletMappings() {
    return new String[] { "/" };
    }

    }
    ---------------------------------------

    @ModelAttribute on a method

    @Controller
    class DemoController {

    // This will be available in all methods of this controller + its JSP.
    @ModelAttribute
    public void addCommonAttributesToModel(Model model1) {
    model1.addAttribute("headerName", "DEMP APP");
    }

    }

    -----------------------------------
    Data mapping with @ModelAttribute

    <form>
    input name="address.line1"
    input name="address.line2"
    </form>

    class user {
    private Address address
    }

    class Address {
    private String line1;
    private String line2;
    }

    -------------------------------
    BindingResult:

    class user {
    private Integer age; // "ABC" => Data Binding Error
    }


    public ModelAndView add(@ModelAttribute("userForm") User user, BindingResult result) {

    if(result.hasError()) {
    return new ModelAndView("add.jsp");
    }
    }

    add.jsp:

    use below from taglib
    <form:errors path="userForm.*"

    -------------------------------------------------
    initBinder:

    @controller
    class C

    @InitiBinder
    p v anyName(WebDataBinder binder) {

    // stop default binding
    binder.setDisallowedFields(new String[] { "someFieldName"});

    // Custom date field binding.
    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd h:m a");
    binder.registerCustomEditor(Date.class, "someDateField", new CustomDateEditor(dateFormat, false));

    }
    }

    Writing your own editor by extending built-in property editor for different data types
    class MyFieldEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
    // do your update
    return super.getAsText();
    }

    // when we submit data, sprign will call setAsText
    @Override
    public void setAsText(String text) throws IllegalArgumentException {
    // do your update
    setValue(text);
    }

    }

    and then in the initbinder method:
    binder.registerCustomEditor(Date.class, "someField", new MyFieldEditor());

    ------------------------

    Form validation using JSR:

    include 3rd part jsr library: hibernate validator

    Class User {

    @Size(min=2, max=10)
    private Integer phone
    }

    public ModelAndView add(@valid @ModelAttribute("userForm") User user, BindingResult result) {

    if(result.hasError()) {
    return new ModelAndView("add.jsp");
    }
    }

    Class User {
    @Size(min=2, max=10, message="Plz enter between 2-10")
    private Integer phone
    }

    Class User {
    @Size(min=2, max=10, message="Plz enter between {min}-{max}")
    private Integer phone

    @Pattern(regexp="..")
    private String name

    @Past
    private Date dateOfBirth
    }

    Customize error message using MessageSource:
    ========================

    <bean id="messageSource"
    class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basename" value="WEB-INF/messages/projectMessages" />

    <property name="basenames">
    <list>
    <value>classpath:messages/AppMessages</value>
    <value>classpath:messages/AppErrorMessages</value>
    </list>
    </property>

    <property name="defaultEncoding" value="UTF-8" />
    </bean>

    AppErrorMessages.properties:
    Size.phone = Plz enter between {1}-{2}

    Spring will search for Size.attributeName in message source.

    Custom validation annotation: TODO
    =====================

    --------------------------------------
    INTERCEPTOR

    Create a class that extends HandlerInterceptorAdapter & override preHandle() & add entry in xml config file.

    <mvc:interceptors>
    <bean class="com.group.project.vicdw.common.controller.SessionValidatorInterceptor" />
    </mvc:interceptors>

    public class SessionValidatorInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    HttpSession session = request.getSession();
    UserAccessBean user = (UserAccessBean) session.getAttribute(USER_BEAN_IN_SESSION);

    response.getWriter().write("error message") // or any other form of response
    OR
    response.sendRedirect(URL);
    OR
    resp.setHeader("redirectToLogin", "true");
    response.sendError(901);

    return false;

    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    // called after controller method
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    // called after view data got created.
    }

    }

    ----------------------------------------------------------
    INTERNATIONALIZATION

    (1)
    mymessagefile_EN.properties
    field1.label=Name
    field2.label=Age

    JSP:
    <form>
    <label><spring:message code="field1.label" />

    (2)
    url?siteName=FR
    Interceptor: LocaleChangeInterceptor
    <mvc:interceptors>
    <property name="paramName" value="siteName" />
    </mvc:interceptors>

    <bean id="localResolver" class="...CookieLocaleResolver" />

    -----------------------------------------
    EXCEPTIONS
    in controller class add a method with annotation @ExceptionHandler(<Exception>.class)

    class AController {

    @ResponseStatus(value=HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(RuntimeException.class)
    public String ExceptionHandlerMethod(RuntimeException runEx) {
    ...
    return RuntimeException; // => RuntimeException.jsp is rendered.
    }

    }

    -------------------------------------------------------------

    JSON RESPONSE:

    @JsonInclude(JsonInclude.Include.NON_NULL)
    @JsonIgnoreProperties({"createdAt"})
    @JsonPropertyOrder({"student_name", "age", "address"}) //order of json attributes
    class User {

    @JsonProperty("student_name") // will be sent as key in JSON response.
    private String name;

    private address;

    private Integer age;

    private String createdAt;

    }

    -----------------------------

    PATH VARIABLE

    @RequestMapping(value = "/action/{do_action}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<ResponseDTO<Void>> do_action(
    @RequestBody RequestDTO<MyDto, Void> request,
    @PathVariable("do_action") String do_action,
    HttpSession session) throws IOException, ApplicationException {

    return ....;

    }

    ----------------------------------

    RESPONSE TYPE:

    is based on header "ACCEPT".
    Value can be "application/json", "application/xml"
    & jackson library will accordingly send response

    @RequestMapping -> "Produces" forces a response to be of specific type.

    REQUEST TYPE:

    Header "content-Type": application/json => information in the body is of type json {....}

    @RequestMapping -> "Consumes" forces a request of specific type to be processed.

    CUSTOM HEADERS:
    org.springframework.http.HttpHeaders h = new org.springframework.http.HttpHeaders();
    h.add(headerName, headerValue);
    add as an argument to new ResponseEntity instance