Tag Archives: solution

Monitoring session to determine whether the user is online or not

Contents of articles

Scenario description session container add session remove session logout session failure

Supplement: listen to the change of session property. Session is independent of other session sharing schemes

Scene description

In the spring boot project, in order to simplify the message module, if there is a new message, write it to the database first. If the user is online, set newmessage flag = true in the session of the user receiving the message. The front end only needs to poll the session each time, and does not need to visit the database each time
the session needs to be obtained according to the user ID, so if the user logs in successfully, call the put method, log out or if the session fails, call remove.

Session container

Stores the session of the logged in user

public class LoggedUserSessionContext{
	//The default capacity is 16, you can set a reasonable initial value according to the number of visits to your site to avoid frequent expansion at the beginning.
    private static Map<Integer, HttpSession> sessionMap = new ConcurrentHashMap<>(128);

    public static HttpSession putIfAbsent(Integer userId, HttpSession session) {
    	// previously logged in a client, then return that session, to achieve multi-party login session sharing
	    return sessionMap.putIfAbsent(userId, session);        
    }

    public static void remove(Integer userId) {
        sessionMap.remove(userId);
    }
 
    public static HttpSession getSession(Integer userId) {
        return sessionMap.get(userId);
    }

}

Add session

After the user logs in successfully, execute the following code snippet

HttpSession session = LoggedUserSessionContext.getSession(user.getId());
            if(session != null){
                //Use the previously logged in id
                SpringUtil.setCookie("JSESSIONID", session.getId(), 60 * 30);
			}else{
				session = SpringUtil.getRequest().getSession();
				session.setAttribute(SessionKey.USER, user);
				LoggedUserSessionContext.putIfAbsent(user.getId(), session);
			}

After successful registration, execute the following code snippet

HttpSession session = SpringUtil.getRequest().getSession();
			session.setAttribute(SessionKey.USER, user);
			LoggedUserSessionContext.putIfAbsent(user.getId(), session);

Remove session

On cancellation

User user = (User)session.getAttribute(SessionKey.USER);
LoggedUserSessionContext.remove(user.getId());
session.invalidate();

When session fails

Use the listener to monitor the implementation of session and implement the HttpSessionListener interface


import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener
public class SessionListener implements HttpSessionListener {

    //Note: HttpServletRequest's getSession() method, if the current request does not correspond to the session will automatically create a session.
    //Using getSession(false) will not create session, if there is no session corresponding to the current request, it will return null.

   
    //New session created if unknown user browsing
    @Override
    public void sessionCreated(HttpSessionEvent event) {

    }

    //session Destroy User offline, logout login
    @Override
    public void sessionDestroyed(HttpSessionEvent event) throws ClassCastException {
        HttpSession session = event.getSession();
        Object userObj = session.getAttribute(SessionKey.USER);
        if(userObj != null){
        	User user = (User)userObj;
        	LoggedUserSessionContext.remove(user.getId());
        }
        
    }

}

Supplement:

Listen for the change of session property


With HttpSessionAttributeListener * * it is not recommended to listen to HttpSessionAttributeListener * * because it is too frequent

import java.util.HashSet;

import javax.servlet.ServletContext;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

@WebListener
public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener {

    //注Meaning: HttpServletRequest's getSession() method, if the current request does not correspond to the session will automatically create a session.
    //use getSession(false) will not create session, if there is no session corresponding to the current request, it will return null.

    //add property user login 
    @Override
    public void attributeAdded(HttpSessionBindingEvent httpSessionBindingEvent) {
        HttpSession session = httpSessionBindingEvent.getSession();
    }

    //Delete Properties User Logout
    @Override
    public void attributeRemoved(HttpSessionBindingEvent httpSessionBindingEvent) {
        logger.info("--attributeRemoved--");
    }

    //Property substitution Information change
    @Override
    public void attributeReplaced(HttpSessionBindingEvent httpSessionBindingEvent) {
        
    }

    //New session creation If unknown user browsing
    @Override
    public void sessionCreated(HttpSessionEvent event) {
        HttpSession session = event.getSession();
        MySessionContext.AddSession(event.getSession());
    }

    //session Destroy User offline, logout login
    @Override
    public void sessionDestroyed(HttpSessionEvent event) throws ClassCastException {
        HttpSession session = event.getSession();
        MySessionContext.DelSession(session);
    }

}

Session independence

Instead of sharing sessions, you can use code logic to set pseudo sharing and change the container and data structure where sessions are stored

 private static Map<Integer, List<HttpSession>> sessionMap  = new ConcurrentHashMap<>(128);

In this way, each terminal can use session without affecting each other.

Destructor abnormal stuck bug

The cause of the bug

When sending messages, this interface needs to be rewritten. If the rewritten method throws an exception and does not capture it, the program will be stuck and will not execute the
Destroy source code

package com.lmax.disruptor;

public interface EventTranslatorVararg<T> {
    void translateTo(T var1, long var2, Object... var4);
}

Problem code

public class Main {
    public static void main(String[] args) {
        Disruptor<Message> disruptor = new Disruptor<>(
                Message::new,
                1024,
                (ThreadFactory) Thread::new);
        disruptor.handleEventsWith((EventHandler<Message>) (message, l, b) -> {
            System.out.println("Handling messages " + message);
        });
        disruptor.start();
        RingBuffer<Message> ringBuffer = disruptor.getRingBuffer();

        for(int i = 0; i<10; i++){
            Message message = new Message(String.valueOf(i));
            ringBuffer.publishEvent((m, l) -> 
            	throw new RuntimeException();
            );// Throwing exceptions without catching and finding that the program cannot be terminated
        }

        System.out.println("hi");	//hi Will not output
        disruptor.shutdown();//shutdown the disruptor, the method will block until all events have been handled.
    }
    
}

result:

The main thread exits, but the program continues to run without stopping

solve:

Handle exceptions on call

public class Main {
    public static void main(String[] args) {
        Disruptor<Message> disruptor = new Disruptor<>(
                Message::new,
                1024,
                (ThreadFactory) Thread::new);
        disruptor.handleEventsWith((EventHandler<Message>) (message, l, b) -> {
            System.out.println("Handling messages " + message);
        });
        disruptor.start();
        RingBuffer<Message> ringBuffer = disruptor.getRingBuffer();

        for(int i = 0; i<10; i++){
            Message message = new Message(String.valueOf(i));
            ringBuffer.publishEvent((m, l, m2) -> {
                try {
                    throw new RuntimeException();
                }catch (Exception e){
                    e.printStackTrace();
                }
            });// Handle exceptions, find program print exceptions and can end
        }

        System.out.println("hi");
        disruptor.shutdown();//Close the disruptor and the method will block until all events have been processed.
    }
    
}

Message.java

public class Message {
    String id;

    public Message(String id) {
        this.id = id;
    }

    public Message() {
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id='" + id + '\'' +
                '}';
    }

}

Error:Cannot build artifact xxx:war exploded’ because it is included into a circular dependency

Error:Cannot build artifact xxx:war exploded’ because it is included into a circular dependency solution
IDEA error: Error:Cannot build artifact xxx:war exploded’ because it is included into a circular dependency

How to Solve:
ctrl + alt + shift + s Open project structure (or ctrl alt + a to search for project structure)
Click on the left artifacts and delete the two extra ones, which are
xxx:warxxx:war exploded
Delete is OK

Termux setting path environment variable

Problem description

When using termux, it is found that the permissions are not enough by using commands. After switching to root by using Su, it is found that many previous commands cannot be used

First, echo $path to view the environment variable of root

Results: in/SBIN/Su/Su/bin/Su/xbin/system/bin/system/xbin

It is found that these three are all in the root path, without/data/data/com.termux/files/usr/bin, so the command here can’t be executed naturally

Exit switch to normal user.

Echo $path view environment variables

The value is/data/data/com. Termux/files/usr/bin/data/data/com. Termux/files/usr/bin/applets

That is to say, you just need to tell root the variables of ordinary users

Here is the solution——————————————————————————————-

In order to ensure the security of the system, the temporary variable is used to save the error

export PATH=/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/bin/applets:$PATH

(tell root the executable

Note that there is no space beside the equal sign, the colon in English: segmentation, the front part is the path value of ordinary users: the Lib path of ordinary users (because some commands also need the library files we download), just paste it

export LD_ LIBRARY_ PATH=/data/data/com.termux/files/usr/lib

(link LIB)

be careful!! For the sake of safety, the operation I posted is temporary. Exit will restore the original identity or turn it off or reopen it. But it’s absolutely safe.

For your convenience, you can create a script to quickly use the downloaded function.

Cd ~ (home directory)

VIM getmytermuxorders (create a file)

Enter the following:

#!/bin/bash
export PATH=/data/data/com.termux/files/usr/bin:/data/data/com.termux/files/usr/bin/applets:$PATH
export LD_LIBRARY_PATH=/data/data/com.termux/files/usr/lib
echo "LYM_nb" 

: WQ save exit

Then exit returns to the original user

When you want to use the root permission again in the future:

Su or TSU comes to root

Run the source command directly in the home directory

source getMyTermuxOrders

If output lym_ NB means that all bin functions of termux have been obtained

You can also use export, echo $path, env and other commands to confirm

Spring boot real time HTML page

Add the following configuration in application. Properties

spring.thymeleaf.cache=false # close cache

Introduce debugging tools into POM. XML and set it to open

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
</dependency>

alt + ctrl + S open settings:
Build,Execution,Deployment —— Complier:
Check Build project automatically
ctrl + shift + alt + /:
Check Registry
Check compiler.automake.allow.when.app.running

The matching result of Python XPath is null

When writing Python crawlers, in order to save time, you usually open F12 in the browser and right-click to copy XPath.

There is a hole in Google browser, which took half a day


The copied XPath is as follows in
Python:// * [@ id = “mainframe”]/div/table/tbody/TR/TD [1]// text ()


Use the browser plug-in XPath helper to test the match successfully!


In the Python code, you can’t match it, as follows

xxx.xpath('//*[@id="mainFrame"]/div/table/tbody/tr/td[1]//text()')

The matching result is an empty list.


reason:

The browser “optimizes” the XPath, so that the XPath copied directly from the browser can’t be run in Python.

Solution:

Delete the extra tbody. The code is as follows:

#There is an extra tbody, delete it
xxx.xpath('//*[@id="mainFrame"]/div/table/tbody/tr/td[1]//text()')
# The modified code is as follows and successfully matches.
xxx.xpath('//*[@id="mainFrame"]/div/table/tr/td[1]//text()')

Playing audio in termux

I have tried all kinds of apt install software, using Python library to write code to run (all kinds of libraries are not available), using java to write code to run (using Android’s own API), all failed. The reasons all point to one point: there is no default audio.

Analysis: because the execution environment is termux, there is no default setting in termux. Android is the real system of the outer system of termux. As long as the sound card, driver, default device and so on are set in termux, they can also be executed after setting.

Here’s a simpler way:

Premise: tinyalsa, root identity, a 44.1KHz audio, turn on the volume

Play command:

./tinyalsa play ~/test.wav

 
View command:

/tinyalsa tinymix

./tinyalsa tinypcminfo -D /proc/asound/cards

cat /proc/asound/cards

 
Set the output device to speaker:

/tinyalsa tinymix 0 SPK

 
Write the play command into a script, give him permission, you can play and use it freely!

After a variety of searches, a better solution was found:

Better and simpler solutions

Eclipse gets stuck saving copy and paste

When editing long code in eclipse, eclipse often gets stuck for a long time when using Ctrl.  
the guess is that you can click and jump to the variable definition after holding down Ctrl in eclipse, so when you press Ctrl, eclipse will generate this mapping. When the file is large, this behavior will take a lot of time. You can set shortcut keys by the following methods.  

Eclipse — Windows-> Preferences-> General-> Editors-> Text Editors-> Hyperlinking:  
Remove this option: enable on demand hyperlinks style navigation