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).