Based on Springboot and WebScoket to write an online chat small procedures

(I haven’t written anything for a few days, and HAVEN’t gone to practice, so I just read this…)

Project description

  • This project is a small demo chat, using Springboot + Websocket + Vue development.
  • One of the interfaces is the Add Friend interface, adding a friend will determine whether they are already friends.
  • During chatting: USER A sends A message to user B. If user B’s chat window is not user A’s, user B will prompt user A to send A message.
  • The input box of chat content adopts layui’s rich text editor, and currently does not support carriage return to send content.
  • Chat can send pictures, which are stored in D:/chat/ by default.
  • Clicking on an image in the chat brings up a preview that brings up all the images in the message.
  • By default, voice messages are sent to users in the current chat window. Therefore, ensure that the selected users are available in the current chat window when recording voice messages.
  • You can add friends if you know the user’s account. At present, you can add friends if the account exists

As usual, let’s look at the small project directory structure first:

First, introduce poM files

I only put a little bit of code here (it’s too long)

<dependency> <groupId> Commons -io</groupId> <artifactId> Commons -io</artifactId> <version>2.4</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> < the groupId >.net. Sf. Json - lib < / groupId > < artifactId > json - lib < / artifactId > < version > 2.4 < / version > <classifier>jdk15</classifier> </dependency> <! -- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> < version > 2.2.4. RELEASE < / version > < / dependency > < the dependency > < groupId > com. Alibaba < / groupId > < artifactId > fastjson < / artifactId > < version > 1.2.60 < / version > < / dependency > < the dependency > <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>Copy the code

2. Create the corresponding YML configuration file

spring:
  profiles:
    active: prod
Copy the code
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/chat? useUnicode=true&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.jdbc.Driver
    # specify data source
    type: com.alibaba.druid.pool.DruidDataSource

    Other configuration of data source
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    # Configure the filters for monitoring statistics interception. After removing the filters, the MONITORING interface SQL cannot be counted. 'wall' is used for the firewall
    filters: stat,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true; druid.stat.slowSqlMillis=500

  thymeleaf:
    suffix: .html
    prefix:
      classpath: /templates/
    cache: false

  jackson: The format of the returned date field
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
    serialization:
      write-dates-as-timestamps: false # true Displays the time using a timestamp
  http:
    multipart:
      max-file-size: 1000Mb
      max-request-size: 1000Mb
Config file development
mybatis:
  Location of the global configuration file
  config-location: classpath:mybatis/mybatis-config.xml
  The location of all SQL mapping configuration files
  mapper-locations: classpath:mybatis/mapper/**/*.xml

server:
  session:
    timeout: 7200
Copy the code

Create an entity class

Here is no longer say more, with the Login, the Userinfo, ChatMsg, ChatFriends

Create the corresponding MAPper (dao layer) and the corresponding mapper mapping file

(Here is just one, no more details)

public interface ChatFriendsMapper {
    // Query all friends
    List<ChatFriends> LookUserAllFriends(String userid);
    // Insert a friend
    void InsertUserFriend(ChatFriends chatFriends);
    // Determine whether to add friends
    Integer JustTwoUserIsFriend(ChatFriends chatFriends);
    // Query user information
    Userinfo LkUserinfoByUserid(String userid);
}
Copy the code
<?xml version="1.0" encoding="UTF-8"? >

      
<mapper namespace="com.chat.mapper.ChatFriendsMapper">
    <select id="LookUserAllFriends" resultType="com.chat.bean.ChatFriends" parameterType="java.lang.String">
      select userid,nickname,uimg from userinfo where userid in (select a.fuserid from chat_friends a where a.userid=#{userid})
    </select>
    <insert id="InsertUserFriend" parameterType="com.chat.bean.ChatFriends">
        insert into chat_friends (userid, fuserid) value (#{userid},#{fuserid})
    </insert>
    <select id="JustTwoUserIsFriend" parameterType="com.chat.bean.ChatFriends" resultType="java.lang.Integer">
        select id from chat_friends where userid=#{userid} and fuserid=#{fuserid}
    </select>
    <select id="LkUserinfoByUserid" parameterType="java.lang.String" resultType="com.chat.bean.Userinfo">
        select * from userinfo where userid=#{userid}
    </select>
</mapper>
Copy the code

Create the corresponding business class (service)

(The same business layer is also pointed out here)

@Service
public class ChatFriendsService {
    @Autowired
    ChatFriendsMapper chatFriendsMapper;
    public List<ChatFriends> LookUserAllFriends(String userid){
        return chatFriendsMapper.LookUserAllFriends(userid);
    }
    public void InsertUserFriend(ChatFriends chatFriends){
        chatFriendsMapper.InsertUserFriend(chatFriends);
    }
    public Integer JustTwoUserIsFriend(ChatFriends chatFriends){
        return chatFriendsMapper.JustTwoUserIsFriend(chatFriends);
    }
    public Userinfo LkUserinfoByUserid(String userid){
        returnchatFriendsMapper.LkUserinfoByUserid(userid); }}Copy the code

6. Create a controller

Let’s talk about the project interface

  1. /chat/upimg Interface for uploading chat pictures
  2. The /chat/lkuser interface is used to add friends. If the user exists, the user information is returned. If the user does not exist, the user information is returned
  3. The /chat/adduser/ interface is used to add friends. It checks whether the added friend is the user and returns the value if the added friend already exists
  4. /chat/ct The chat page is displayed
  5. /chat/ lkFriends Queries a user’s friends
  6. /chat/lkuschatmsg/ This interface is used to query the chat information between two users. The user’s userID is passed in to query the chat records of the current logged-in user and the user.
  7. The /chat/audio interface is used by Ajax to upload audio data recorded by JS on the Web interface

(Again, just write one)

@Controller
public class LoginCtrl {
    @Autowired
    LoginService loginService;
    @GetMapping("/")
    public String tologin(a){
        return "user/login";
    }
    /** * log in ** /
    @PostMapping("/justlogin")
    @ResponseBody
    public R login(@RequestBody Login login, HttpSession session){
        login.setPassword(Md5Util.StringInMd5(login.getPassword()));
        String userid = loginService.justLogin(login);
        if(userid==null) {return R.error().message("Wrong account or password");
        }
        session.setAttribute("userid",userid);
        return R.ok().message("Login successful"); }}Copy the code

Create the corresponding tool class and custom exception class

  1. Expression filtering tool class
public class EmojiFilter {
    private static boolean isEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) || (codePoint == 0x9) || (codePoint == 0xA)
                || (codePoint == 0xD)
                || ((codePoint >= 0x20) && (codePoint <= 0xD7FF))
                || ((codePoint >= 0xE000) && (codePoint <= 0xFFFD))
                || ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }

    @Test
    public void testA(a){
        String s = EmojiFilter.filterEmoji("Hello 😄, how are you?");
        System.out.println(s);
    }

Copy the code
  1. Md5 data encryption class
   static String[] chars = {"0"."1"."2"."3"."4"."5"."6"."Seven"."8"."9"."a"."b"."c"."d"."e"."f"};

    /** * encrypts an ordinary string with MD5 and converts it to a hexadecimal string *@param str
     * @return* /
    public static String StringInMd5(String str) {

        // Message signature (digest)
        MessageDigest md5 = null;
        try {
            // The parameter represents the algorithm name
            md5 = MessageDigest.getInstance("md5");
            byte[] result = md5.digest(str.getBytes());

            StringBuilder sb = new StringBuilder(32);
            // Convert the result to hexadecimal characters 0 to 9 A to F
            for (int i = 0; i < result.length; i++) {
                // One byte corresponds to two characters
                byte x = result[i];
                // get a high position
                int h = 0x0f & (x >>> 4);
                // get the low value
                int l = 0x0f & x;
                sb.append(chars[h]).append(chars[l]);
            }
            return sb.toString();

        } catch (NoSuchAlgorithmException e) {
            throw newRuntimeException(e); }}Copy the code
  1. Test data encryption classes
public class TestUtil {
    @Test
    public void testA(a){
        String s = Md5Util.StringInMd5("123456"); System.out.println(s); }}Copy the code

8. Introduce the corresponding static resource file (this should be done at the beginning)

9. Customize some configurations and inject them into the container

  1. Druid data source
@Configuration
public class DruidConfig {
    @ConfigurationProperties(prefix = "spring.datasource")
    @Bean
    public DataSource druid(a){
        return new DruidDataSource();
    }
    // Configure Druid monitoring
    //1. Configure the Servlet to be assigned to the admin background
    @Bean
    public ServletRegistrationBean servletRegistrationBean(a){
        ServletRegistrationBean bean=new ServletRegistrationBean(new StatViewServlet(),"/druid/*");
        Map<String,String> initParams=new HashMap<>();
        initParams.put("loginUsername"."admin");
        initParams.put("loginPassword"."admin233215");
        initParams.put("allow"."");// IP access is allowed by default
        initParams.put("deny"."");
        bean.setInitParameters(initParams);
        return bean;
    }
    //2. Configure a filter for monitoring
    @Bean
    public FilterRegistrationBean webStarFilter(a){
        FilterRegistrationBean bean=new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter());
        Map<String,String> initParams=new HashMap<>();
        initParams.put("exclusions"."*.js,*.css,/druid/*");
        bean.setInitParameters(initParams);
        bean.setUrlPatterns(Arrays.asList("/ *"));
        returnbean; }}Copy the code
  1. Static resources and interceptors
@Configuration
public class MyConfig extends WebMvcConfigurerAdapter {
    Otherwise, CSS and JS cannot be used. The default static resource is static, but the folder inside is not configured
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
    @Bean
    public WebMvcConfigurerAdapter WebMvcConfigurerAdapter(a) {
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addResourceHandlers(ResourceHandlerRegistry registry) {
                //registry.addResourceHandler("/pic/**").addResourceLocations("file:D:/chat/");
                registry.addResourceHandler("/pic/**").addResourceLocations("file:D:/idea_project/SpringBoot/Project/Complete&&Finish/chat/chatmsg/");
                super.addResourceHandlers(registry); }};return adapter;
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // Register TestInterceptor interceptor
        InterceptorRegistration registration = registry.addInterceptor(new AdminInterceptor());
        registration.addPathPatterns("/chat/*"); }}Copy the code
  1. WebSocketConfigScokt Communication configuration
@Configuration
@EnableWebSocket
public class WebSocketConfig {
 
    @Bean
    public ServerEndpointExporter serverEndpointExporter(a) {
        return newServerEndpointExporter(); }}Copy the code

10. Test

These are two different users

Of course, you can also make voice calls and add friends
That’s all for today! Thank you very much!
I want to mention the personal blog of one of my upperclassmen and, of course, mine. Thank you

Richard wood guest

my

The end of the world will