The filter

In daily life, I believe that we should more or less have seen filters, such as filters, filter paper, etc.; These are all filters

It filters out things we don’t need, and filters in JavaWeb refer to classes that implement the Javax.servlet.filter interface

We can use filter technology to intercept all Web resources managed by the Web server, such as JSPS, servlets, static image files, or static HTML files

In order to achieve some special functions, such as the implementation of URL-level access control, filtering sensitive words, compression of response information…

Its simplest application is to deal with garbled code in advance before we access the Servlet class we have written

As mentioned earlier, if we directly use writer object to print Chinese string to the front end, there will be garbled characters. So this is the case down here

This small problem should be the first one you encounter when learning JavaWeb, and it is fairly easy to solve; We just need to add this dead line of code to our servlet class

// Must be added to the first line
resp.setContentType("text/html; charset=UTF-8");
Copy the code


The reason for the garble problem is that the code used by Tomcat is ISO-8859-1 by default, which is commonly used in European countries. Support for Chinese is not ideal

If you want to display Chinese characters normally, you can use UTF-8, GB2312, GBK, etc. Utf-8 is international, so most cases will use UTF-8 to solve the problem of Chinese garbled characters.

Although a single line of dead code can solve the problem of garbled characters responding to the front end, there can be a lot of garbled characters; Garbled characters can occur not only in response, but also in requests

We can’t, or should not, add these garbage-proof dead codes to every servlet class

If you want to solve this problem well, a filter is a good choice

We can avoid the garble problem by simply passing through a filter (which prehandles the garble) every time we access a Web resource

Having said that, and still not really getting started with filters, let’s take a look at the simplest way to use filters to deal with garbled characters


Simple filter

Using the filter is very simple; we just need to implement the filter interface and register it with web.xml

As you can see, the Filter interface is very many, we will implement javax.servlet; How about you don’t have this interface to check if your dependencies are imported properly

<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>servlet-api</artifactId>
    <version>2.5</version>
</dependency>
Copy the code

Once the interface is implemented, we have to override its three methods, init(); And destory (); Methods we don’t need to deal with for the moment; We write dead code to doFiter() that deals with garbled code; In the can.

public class CharacterEncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        / / initialization
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // Handle garbled characters
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        
        // Let the filter pass, this step is necessary; You could try not to write this, right
        chain.doFilter(request,response);
    }

    @Override
    public void destroy(a) {
        / / destroy}}Copy the code

Register the written filter with web.xml and configure the path that the filter needs to filter

<filter>
    <filter-name>characterEncoding</filter-name>
    <filter-class>com.molu.demo.CharacterEncodingFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>characterEncoding</filter-name>
    <! Filter all request paths -->
    <url-pattern>/ *</url-pattern>
</filter-mapping>
Copy the code

Once this is done, we can test it by deleting the dead code that handles garble in the Servlet class

You’ll find that your garble problem is basically solved and that’s the simplest application of filters — to deal with garble


Filter chain

The existence of filters can be single or multiple; If there are multiple filters in a Web service that can be combined with each other, we call it a filter chain

For example, during the login operation, we need to verify not only the correct account password entered by the user, but also the sufficient permissions of the logged in user

In this case we can write two or more filters that handle different filtering logic.

The Web server decides which filter to invoke first based on the order in which the filters are registered in the web.xml file

When the doFilter(): method of the first filter is called, the Web server creates a FilterChain object representing the FilterChain and passes it to the method.

DoFilter () in the filter; Method, if we call doFilter() of FilterChain; Method, the Web server checks to see if any filters exist in the FilterChain object, calls the second filter if so, and returns the target resource if not.

That’s why AT the end I said let the filter pass, which is a necessary step a line comment, if you don’t call doFilter() of the FilterChain object at the end; Method, then you will be blocked by the filter and cannot access the corresponding resource.


Filter life cycle

The Web server is responsible for the creation and destruction of filters, and the time between the creation and destruction of filters is called the filter life cycle

Filter creation

When the Web application starts, the Web server creates an instance object of the filter and calls its init(); Method to complete the initialization function of the object, thus preparing for the interception of subsequent user requests.

Filter objects are created only once, init(); Methods are executed only once, by init(); Method to obtain a FilterConfig object representing the current filter configuration information.

Filter destruction

When we shut down the Web server, the instance object of the filter is destroyed and its destory() is called; methods

destroy(); The destroy() method is executed only once in the life of the filter; Method, write some code that frees resources


The listener

First understand what a listener is. Some beginners might be a little confused when they hear the word listener, but it’s not as complicated as you might think.

A listener is an object that listens for and handles specific events or state changes that occur on other objects

A listener is simply a plain Java program that implements a specific interface and listens specifically for method calls or property changes on another Java object.

A listener method is executed immediately after the listener event.

This may sound a bit cloudy, especially for beginners

Of course, if you know anything about GUI programming, you should be familiar with listeners

What’s the easiest way to think about a listener, like if you open a browser, there should always be a button in the top right of the browser that closes the browser

The browser is closed when we click this button, because the button is bound to a listening event that closes the browser; When we click the button the listener event is triggered and the browser is closed.

In JavaWeb, the listener is also used less and less, it is like the GUI slowly forgotten, many courses face this thing is a brush

It is because these things learn less and less people, beginners learn more difficult, search articles blog words are difficult to find help, so I am not going to write this kind of things perfunctory.


Listeners in JavaWeb

Listeners in JavaWeb are a special class defined in the Servlet specification that listens for creation and destruction events of domain objects such as ServletContext, HttpSession, and ServletRequest in Web applications. And listen for events in which properties in these domain objects have changed.

Statistics the number of online Demo

Enough good theory, let’s write a simple Demo that counts the number of people who are currently online, and get to know the listener.

Overriding methods

// Implement a listener that listens for the number of sessions in the current Web service; It can be understood simply as the number of online statistics

// First we need to implement the listener interface specified by the Servlet
public class OnlineCountListener implements HttpSessionListener {
    // Implementing the interface will have to override the following two methods
    @Override
    public void sessionCreated(HttpSessionEvent se) {
        // This method is called when a Session is created

        // Get the context object
        ServletContext context = se.getSession().getServletContext();
        Integer onlineCount = (Integer) context.getAttribute("onlineCount");
        // If the onlineCount variable is 0 when the Session creation listener event is triggered, we set it to 1 to indicate that the first user is online
        if (onlineCount==null){
            onlineCount = new Integer(1);
            // If the value is not 0, the number of users who have been online before is +1
        }else {
            int count = onlineCount.intValue();
            onlineCount = new Integer(count+1);
        }
        // Printout is easy to test, can be removed
        System.out.println(onlineCount);
        // Add the variable assignment of the number of people online to the context object to facilitate the front-end value
        context.setAttribute("onlineCount",onlineCount);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent se) {
        // This method, by contrast, is called when the Session is destroyed

        // Destroy part of the logic is the opposite
        ServletContext context = se.getSession().getServletContext();
        Integer onlineCount = (Integer) context.getAttribute("onlineCount");
        if (onlineCount==null){
            onlineCount = new Integer(0);
        }else {
            int count = onlineCount.intValue();
            onlineCount = new Integer(count-1);
        }
        context.setAttribute("onlineCount",onlineCount); }}Copy the code

Register listeners

After the listener is written, we need to register it with web.xml, just like the filter

<listener>
    <! Filter registration is relatively simple -->
    <listener-class>com.molu.listener.OnlineCountListener</listener-class>
</listener>
Copy the code

Let’s write another JSP that can get and display the number of people online

<body> <div> <h2> <span style="background-color: aquamarine">
            ${applicationScope.get("onlineCount")}
        </span>
    </h2>
</div>
</body>
Copy the code

test

Successfully through the listener to achieve a simple website online number of statistics

This is done by implementing the HttpSessionListener interface, a listener that listens for Session creation and destruction;

We can also implement the ServletContextListener interface and write a listener that listens for the creation and destruction of the ServletContext (the creation and destruction of context objects are at the server level, similar to the filter lifecycle).

Implement the ServletRequestListener interface and write a listener that listens for the creation and destruction of a ServletRequest (the ServletRequest object is created at access time and destroyed after access).

These are all basically similar, so I’m not going to write them all; You can test it out for yourself


Listen for changes to domain object properties

An event listener for a property change in a domain object is a listener for a property change event in ServletContext, HttpSession, and HttpServletRequest. The three listener interface is ServletContextAttributeListener, HttpSessionAttributeListener and ServletRequestAttributeListener respectively

Each of these interfaces defines three methods to handle the addition, deletion, and replacement of attributes in the monitored object. The same event corresponds to the same method name in all three interfaces, but accepts different parameter types.


attributeAdded

Implementing any AttributeListener interface requires you to override a similar attributeAdded(); Method that fires when you add a property to the corresponding listener domain object.

For example, you implement the ServletContextAttributeListener interface, then you need to rewrite its corresponding attributeAdded (); Method that is fired when a new property is added to the context object.

Whether attributeAdded (); Method, or any other method that listens for changes in the attributes of a domain object, has a XXXXXAttributeEvent object, which is used to retrieve both the monitored domain object itself and the changed attributes of the monitored domain object.

Here is the sample code

/ / implementation ServletContextAttributeListener interface, the three listener interface here is similar not implemented one by one
public class ContextAttributeListener implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent scab) {
        / / we can get the context object by ServletContextAttributeEvent object
        ServletContext context = scab.getServletContext();
        // We can also use it to fetch the name and value of our new attributes
        context.setAttribute("attributeName",scab.getName());
        context.setAttribute("attributeValue",scab.getValue());
    }
    @Override
    public void attributeRemoved(ServletContextAttributeEvent scab) {}@Override
    public void attributeReplaced(ServletContextAttributeEvent scab) {}Copy the code

After implementing the interface, we override the corresponding three methods that listen for attribute changes. Let’s first look at attributeAdded();

The listener must be registered after writing, otherwise it will not take effect without writing

<listener>
    <listener-class>com.molu.listener.ContextAttributeListener</listener-class>
</listener>
Copy the code

Before testing, let’s write some JSP for testing to facilitate testing

<! <body> <div> <h3> <p> ${applicationScope.get()"attributeName"}</p> <p></p> <p>"attributeValue")}</p>
    </h3>
</div>
</body>
Copy the code
<! <body> <% application.setAttribute()"nickname"."Stranger"); </h4> </div> </body>Copy the code

test

No problem, we successfully pass attributeAdded(); The listener gets the name and value of our new property.


attributeRemoved

These three methods are actually similar, and the attributeAdded method that we copied to this one can be used directly, even without modification

Whenever we delete an attribute in the context object, this method gets the name and value of that attribute. And then it goes to the front end

@Override
public void attributeRemoved(ServletContextAttributeEvent scab) {
    / / we can get the context object by ServletContextAttributeEvent object
    ServletContext context = scab.getServletContext();
    // We can also use it to fetch the name and value of the attributes we deleted
    context.setAttribute("attributeName",scab.getName());
    context.setAttribute("attributeValue",scab.getValue());
}
Copy the code

Corresponding to we need to modify the previous JSP file, convenient test

The < body > < % - the index - % > < div > < h3 > < p > delete attribute is: ${applicationScope. Get ("attributeName"}</p> <p></p> <p>"attributeValue")}</p>
    </h3>
</div>
</body>


<body>
<%--update--%>
<%
    /*application.setAttribute("onlineCount",999); * /
    application.removeAttribute("onlineCount"); </h4> </div> </body>Copy the code

test

No problem, we just remove the attribute in the context object, and the attributeRemoved() is triggered; methods

So the remaining attributeReplaced(); I’m not going to go over it again; It doesn’t make any sense. You can test yourself if you’re interested


Event listeners that are aware of Session bindings

Objects stored in the Session domain can have multiple states

  • Bind to Session(session.setAttribute("bean",Object));
  • Unbind from the Session domain(session. RemoveAttribute (" bean "));
  • Persist the Session object to a storage device
  • Recover from a storage device with the Session object

The Servlet specification defines two special listener HttpSessionBindingListener and HttpSessionActivationListener interface to help the JavaBean object understand oneself in the Session domain of the state

Classes that implement these two interfaces do not need to be registered in the web.xml file


HttpSessionBindingListener

Implements HttpSessionBindingListener interface JavaBean objects need to rewrite the two methods: valueBound (); And valueUnbound (); When the JavaBean is bound to the Session object, the Web server calls valueBound() overridden by the JavaBean; Otherwise (remove from Session) valueUnbound() is called; methods

Let’s write the code to make sure:

/ / implementation HttpSessionBindingListener interface
public class User implements HttpSessionBindingListener {
    private int age;
    private String name;

    Getters, setters, constructors, etc. are omitted below.// Two methods that must be overridden
    @Override
    public void valueBound(HttpSessionBindingEvent event) {
        System.out.println("User is bound to Session");
    }

    @Override
    public void valueUnbound(HttpSessionBindingEvent event) {
        System.out.println("User removed from Session"); }}Copy the code

Ok, now let’s write a few more simple JSPS

<body>
<%-- add --%>
<%
    // Add the corresponding Javabeans to the Session object
    session.setAttribute("User".new User(18."Stranger")); Successful % > < div > < h3 > add < / h3 > < / div > < / body > < body > < % - remove % > < % session. The removeAttribute ("User"); </h3> </div> </body>Copy the code

These JSPS are very simple and do nothing more than add and remove Javabeans into the Session object.

test

No problem. By looking at the console, we can confirm that adding or removing a JavaBean User from the Session object triggers its corresponding listening event.


HttpSessionActivationListener

Implements the HttpSessionActivationListener interface javabeans can perceive themselves as serialization or deserialization

To implement it we need to override two methods: sessionWillPassivate(); And sessionDidActivate ();

When the JavaBean object bound to the Session object is about to be passivated (serialized) with the Session object, the Web server calls the sessionWillPassivate() of the JavaBean object; Methods;

In this way, the JavaBean object knows that it will be serialized (passivated) to hard disk along with the Session object. After the JavaBean object bound to the Session object is about to be activated (deserialized) with the Session object, the Web server calls the JavaBean object’s sessionDidActive(); Methods;

This way the JavaBean object knows that it will be deserialized (activated) back into memory along with the Session object.

I’m sure we don’t need to talk too much about listening events at this point (the only thing that might confuse us is serialization, but this article isn’t going to write about serialization, so you can find someone else to read about it), and we’ll go straight to the code and do a bunch of final tests.

/ / implementation HttpSessionActivationListener interface to monitor serialization and deserialization) operation
public class User implements HttpSessionActivationListener.Serializable {
    private int age;
    private String name;

    Getters, setters, constructors, etc. are omitted below.// Two methods that must be overridden
    @Override
    public void sessionWillPassivate(HttpSessionEvent se) {
        System.out.println(name + "Serialized to hard disk along with Session." + The Session ID is: + se.getSession().getId());
    }

    @Override
    public void sessionDidActivate(HttpSessionEvent se) {
        System.out.println(name + "Deserialized into memory with Session." + The Session ID is:+ se.getSession().getId()); }}Copy the code

In order to observe the process of the JavaBean objects bound to the Session object being serialized to hard disk and deserialized back to memory together with the Session object, we need to use the Tomcat server to help us complete the serialization and deserialization of the Session object. The specific methods are as follows:

Create a meta-INF directory in the root path of your Web project, create a context. XML file in that directory, and bake in the code below

<Context>
    <! Serialize the Session object to a test directory on the local disk after 1 minute of configuration in context. XML
    <Manager className="org.apache.catalina.session.PersistentManager" maxIdleSwap="1">
        <Store className="org.apache.catalina.session.FileStore" directory="test"/>
    </Manager>
</Context>
Copy the code

Write some simple code in index.jsp and bind our Javabeans to Session

<body> <%--index--%> <div> <h3> ${pagecontext.session. id} </h3> <div> <p> This session will be serialized to the local disk in one minute </p> </div> </div> <% session.setattribute ("User".new User(18."moluu"));
%>
</body>
Copy the code

To start the server to test, we simply need to go to localhost:8080 and clear the IDE console after correctly displaying the code you wrote in index.jsp

Wait a minute

A minute later you will find that you are writing in sessionWillPassivate(); The output statement in the method is executed

At this point, locate the directory where the tomcat files generated after your IDE configuration is run. In this directory, you will find the generated test directory, and the session serialized to local storage

When you call localhost:8080 again, deserialization will be performed, and the session serialized locally will be returned to memory (serialization will be performed again a minute later).


Relax your eyes

Original picture P station address

Painters home page