Mybatis-plus实战项目演示+自定义元数据对象处理器+ws

news2024/12/27 12:54:46

目录

一,mybatis-plus实战一

1.导入依赖

2.application.yml配置

3.实体类

4.mapper

5.service层

6.启动类上配置

二,mybatis-plus实战二

1.导入依赖

2.application.yml配置

3.实体类

2.mapper

3.service

4.分页配置

5.放一个在controller层实现的mybatis-plus的具体实现

6.启动类上加上注解

三,时间更新全局配置(自定义元数据对象处理器)

1.数据库相关字段配置

2. 实体类配置

四.WebSocket打造在线聊天室

1.导入依赖

2.配置类

 3.工具类

4.controller

5.index.html


一,mybatis-plus实战一

1.导入依赖

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.1</version>
        </dependency>

2.application.yml配置

spring:
  # 配置数据源信息
  datasource:
    # 配置数据源类型
    type: com.zaxxer.hikari.HikariDataSource
    # 配置连接数据库的各个信息
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/intrest?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: 12345678

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
#  # 设置MyBatis-Plus的全局配置
#  global-config:
#    db-config:
#      # 设置实体类所对应的表的统一前缀
#      table-prefix: t_
#      # 设置统一的主键生成策略
#      id-type: auto
#  # 配置类型别名所对应的包
  type-aliases-package: com.interest.pojo
#  # 扫描通用枚举的
 # 包
#  type-enums-package: com.interest.enums


3.实体类

package com.interest.pojo;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author a1002
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("interest")
public class Interest {
    @JsonSerialize(using = ToStringSerializer.class)
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private Long id;
    private String code;
    private String name;
    private String sex;
    private String birthday;
    private String phone;
    private String type;
    private String course;
    private String registerTime;
    private String remaining;
    private String score;

    public Interest(String code, String name, String sex, String birthday, String phone, String type, String course, String registerTime, String remaining, String score) {
        this.code = code;
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
        this.phone = phone;
        this.type = type;
        this.course = course;
        this.registerTime = registerTime;
        this.remaining = remaining;
        this.score = score;
    }
}

4.mapper

package com.interest.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.interest.pojo.Interest;
import org.springframework.stereotype.Repository;

/**
 * @author a1002
 */
@Repository
public interface InterestMapper extends BaseMapper<Interest> {

}

5.service层

package com.interest.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.interest.config.Response;
import com.interest.pojo.Interest;

import java.util.List;
import java.util.Map;

/**
 * @author a1002
 */
public interface InterestService extends IService<Interest> {
    
}
package com.interest.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.interest.config.Response;
import com.interest.mapper.InterestMapper;
import com.interest.pojo.Interest;
import com.interest.service.InterestService;
import com.interest.utils.IDutils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author a1002
 */
@Service
public class InterestServiceImpl extends ServiceImpl<InterestMapper,Interest> implements InterestService {

}

6.启动类上配置

import lombok.extern.slf4j.Slf4j;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author a1002
 */
@Slf4j
@SpringBootApplication
//@ServletComponentScan
@EnableTransactionManagement
@EnableCaching
@MapperScan("com.blog.mapper")
public class BlogApplication {
    public static void main(String[] args) {
        SpringApplication.run(BlogApplication.class, args);
        log.info("项目启动成功...");
    }
}

二,mybatis-plus实战二

1.导入依赖

        <!--mybaties-plus-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.2</version>
        </dependency>

2.application.yml配置

mybatis-plus:
  configuration:
    #在映射实体或者属性时,将数据库中表名和字段名中的下划线去掉,按照驼峰命名法映射
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  global-config:
    db-config:
      id-type: ASSIGN_ID

3.实体类

import lombok.Data;

import java.io.Serializable;


@Data
public class Orders implements Serializable {
}

2.mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yangeat.entity.AddressBook;
import org.apache.ibatis.annotations.Mapper;

/**
 * @author a1002
 */
@Mapper
public interface AddressBookMapper extends BaseMapper<AddressBook> {

}

3.service

import com.baomidou.mybatisplus.extension.service.IService;
import com.yangeat.entity.AddressBook;

/**
 * @author a1002
 */
public interface AddressBookService extends IService<AddressBook> {

}
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yangeat.entity.AddressBook;
import com.yangeat.mapper.AddressBookMapper;
import com.yangeat.service.AddressBookService;
import org.springframework.stereotype.Service;

/**
 * @author a1002
 */
@Service
public class AddressBookServiceImpl extends ServiceImpl<AddressBookMapper, AddressBook> implements AddressBookService {

}

4.分页配置

package com.blog.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置MP的分页插件
 *
 * @author a1002
 */
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

分页实际应用:

@Override
    public R list(int page, int size, String name) {
        Page<User> pageInfo = new Page<>(page, size);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(name != null, User::getUsername, name);
        queryWrapper.orderByDesc(User::getUpdateTime);
        userService.page(pageInfo, queryWrapper);

        return R.success(pageInfo);
    }

5.放一个在controller层实现的mybatis-plus的具体实现

package com.yangeat.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yangeat.common.R;
import com.yangeat.dto.SetmealDto;
import com.yangeat.entity.Category;
import com.yangeat.entity.Setmeal;
import com.yangeat.service.CategoryService;
import com.yangeat.service.SetmealDishService;
import com.yangeat.service.SetmealService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 套餐管理
 */

@RestController
@RequestMapping("/setmeal")
@Slf4j
public class SetmealController {

    @Autowired
    private SetmealService setmealService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SetmealDishService setmealDishService;

    /**
     * 新增套餐
     *
     * @param setmealDto
     * @return
     */
    @PostMapping
    public R<String> save(@RequestBody SetmealDto setmealDto) {
        log.info("套餐信息:{}", setmealDto);

        setmealService.saveWithDish(setmealDto);

        return R.success("新增套餐成功");
    }

    /**
     * 套餐分页查询
     *
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name) {
        //分页构造器对象
        Page<Setmeal> pageInfo = new Page<>(page, pageSize);
        Page<SetmealDto> dtoPage = new Page<>();

        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件,根据name进行like模糊查询
        queryWrapper.like(name != null, Setmeal::getName, name);
        //添加排序条件,根据更新时间降序排列
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        setmealService.page(pageInfo, queryWrapper);

        //对象拷贝
        BeanUtils.copyProperties(pageInfo, dtoPage, "records");
        List<Setmeal> records = pageInfo.getRecords();

        List<SetmealDto> list = records.stream().map((item) -> {
            SetmealDto setmealDto = new SetmealDto();
            //对象拷贝
            BeanUtils.copyProperties(item, setmealDto);
            //分类id
            Long categoryId = item.getCategoryId();
            //根据分类id查询分类对象
            Category category = categoryService.getById(categoryId);
            if (category != null) {
                //分类名称
                String categoryName = category.getName();
                setmealDto.setCategoryName(categoryName);
            }
            return setmealDto;
        }).collect(Collectors.toList());

        dtoPage.setRecords(list);
        return R.success(dtoPage);
    }

    /**
     * 删除套餐
     *
     * @param ids
     * @return
     */
    @DeleteMapping
    public R<String> delete(@RequestParam List<Long> ids) {
        log.info("ids:{}", ids);

        setmealService.removeWithDish(ids);

        return R.success("套餐数据删除成功");
    }

//    @GetMapping("/list")
//    public R<List<Setmeal>> list(Setmeal setmeal) {
//        log.info("setmeal:{}", setmeal);
//        //条件构造器
//        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
//        queryWrapper.like(StringUtils.isNotEmpty(setmeal.getName()), Setmeal::getName, setmeal.getName());
//        queryWrapper.eq(null != setmeal.getCategoryId(), Setmeal::getCategoryId, setmeal.getCategoryId());
//        queryWrapper.eq(null != setmeal.getStatus(), Setmeal::getStatus, setmeal.getStatus());
//        queryWrapper.orderByDesc(Setmeal::getUpdateTime);
//
//        return R.success(setmealService.list(queryWrapper));
//    }

    /**
     * 根据条件查询套餐数据
     *
     * @param setmeal
     * @return
     */
    @GetMapping("/list")
    public R<List<Setmeal>> list1(@RequestBody Setmeal setmeal) {
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(setmeal.getCategoryId() != null, Setmeal::getCategoryId, setmeal.getCategoryId());
        queryWrapper.eq(setmeal.getStatus() != null, Setmeal::getStatus, setmeal.getStatus());
        queryWrapper.orderByDesc(Setmeal::getUpdateTime);

        List<Setmeal> list = setmealService.list(queryWrapper);

        return R.success(list);

    }

    @PostMapping("/status/{status}")
    public R<List<Setmeal>> status(@PathVariable Integer status, @RequestParam List<Long> ids) {
        LambdaQueryWrapper<Setmeal> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(Setmeal::getId, ids);
        List<Setmeal> list = setmealService.list(queryWrapper);
        List<Setmeal> list1 = list.stream().map((item) -> {
            item.setStatus(status);
            return item;
        }).collect(Collectors.toList());
        setmealService.updateBatchById(list1);
        return R.success(list1);
    }
}

6.启动类上加上注解

主要是@ServletComponentScan这个注解

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.transaction.annotation.EnableTransactionManagement;

/**
 * @author a1002
 */
@Slf4j
@SpringBootApplication
@ServletComponentScan
@EnableTransactionManagement
public class YangEatApplication {

    public static void main(String[] args) {
        SpringApplication.run(YangEatApplication.class, args);
        log.info("项目启动成功...");
    }

}

三,时间更新全局配置(自定义元数据对象处理器)

1.数据库相关字段配置

2. 实体类配置

package com.blog.pojo;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * @author a1002
 */
@SuppressWarnings("all")
@Data
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class User implements Serializable {
    private static final long serialVersionUID = 1L;

    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    private String username;
    private String password;
    /**
     * 0是用户
     * 1是管理员
     */
    private Integer status;
    private String img;
    private String blogPath;
    private String grade;

    //创建时间
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    //更新时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    //创建人
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    //修改人
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public User(Long id, String username, String password, String img, String blogPath, String grade) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.img = img;
        this.blogPath = blogPath;
        this.grade = grade;
    }

    public User(Long id, String username, String password, String blogPath, String grade) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.blogPath = blogPath;
        this.grade = grade;
    }


}

其中主要是这些字段

    //创建时间
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;


    //更新时间
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;


    //创建人
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;


    //修改人
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;

相关配置:

主要是这三个配置类:

package com.blog.common;

/**
 * 基于ThreadLocal封装工具类,用户保存和获取当前登录用户id
 *
 * @author a1002
 */
public class BaseContext {
    private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();

    /**
     * 设置值
     *
     * @param id
     */
    public static void setCurrentId(Long id) {
        threadLocal.set(id);
    }

    /**
     * 获取值
     *
     * @return
     */
    public static Long getCurrentId() {
        return threadLocal.get();
    }
}

package com.blog.common;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 *
 * @author a1002
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                .addSerializer(Long.class, ToStringSerializer.instance)
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}
package com.blog.common;

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * 自定义元数据对象处理器
 *
 * @author a1002
 */
@Component
@Slf4j
public class MyMetaObjecthandler implements MetaObjectHandler {
    /**
     * 插入操作,自动填充
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        log.info("公共字段自动填充[insert]...");
        log.info(metaObject.toString());

        metaObject.setValue("createTime", LocalDateTime.now());
        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("createUser", BaseContext.getCurrentId());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }

    /**
     * 更新操作,自动填充
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        log.info("公共字段自动填充[update]...");
        log.info(metaObject.toString());

        long id = Thread.currentThread().getId();
        log.info("线程id为:{}", id);

        metaObject.setValue("updateTime", LocalDateTime.now());
        metaObject.setValue("updateUser", BaseContext.getCurrentId());
    }
}
GlobalExceptionHandler是针对添加用户时避免用户重复添加的异常处理
package com.blog.common;

import com.blog.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 全局异常处理
 *
 * @author a1002
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 异常处理方法
     *
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
        log.error(ex.getMessage());

        if (ex.getMessage().contains("Duplicate entry")) {
            String[] split = ex.getMessage().split(" ");
            String msg = split[2] + "已存在";
            return R.error(msg);
        }

        return R.error("未知错误");
    }

//    /**
//     * 异常处理方法
//     *
//     * @return
//     */
//    @ExceptionHandler(CustomException.class)
//    public R<String> exceptionHandler(CustomException ex) {
//        log.error(ex.getMessage());
//
//        return R.error(ex.getMessage());
//    }

}

四.WebSocket打造在线聊天室

目录

1.导入依赖

        <!--websocket-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.7.2</version>
        </dependency>

2.配置类

package com.websockettest.config;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import javax.websocket.server.ServerEndpointConfig;

/**
 * @author a1002
 */
public class MySpringConfigurator extends ServerEndpointConfig.Configurator implements ApplicationContextAware {

    private static volatile BeanFactory context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        MySpringConfigurator.context = applicationContext;
    }

    @Override
    public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
        return context.getBean(clazz);
    }
}
package com.websockettest.config;

import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * @author a1002
 */
@Configuration
@ConditionalOnWebApplication
public class WebSocketConfig {

    //使用boot内置tomcat时需要注入此bean
    @Bean
    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }


    @Bean
    public MySpringConfigurator mySpringConfigurator() {
        return new MySpringConfigurator();
    }
}

 3.工具类

package com.websockettest.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author a1002
 */
public class DateUtils {
    public static String getDate() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        return format.format(date);


    }
}

4.controller

package com.websockettest.controller;

import com.websockettest.config.MySpringConfigurator;
import com.websockettest.utils.DateUtils;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.util.HashMap;
import java.util.Map;

/**
 * @author a1002
 * @ServerEndpoint 注解是一个类层次的注解,它的功能主要是将目前的类定义成一个websocket服务器端,注解的值将被用于监听用户连接的终端访问URL地址,客户端可以通过这个URL来连接到WebSocket服务器端
 */
@ServerEndpoint(value = "/chat/{uid}", configurator = MySpringConfigurator.class)
@Component
public class WebSocketTest {
    private Session session;


    private String getUid(Session session) {
        this.session = session;
        Map parem = session.getPathParameters();
        String uid = parem.get("uid").toString();
        return uid;
    }

    /**
     * 当前登录人的 session 管理器
     */
    private static Map<String, Session> sessionMessage = new HashMap<>();

    @OnOpen//打开连接执行
    public void onOpw(Session session) {
        String uid = getUid(session);
        sessionMessage.put(uid, session);
        System.out.println("[" + uid + "] 进入聊天室");
        sendMessage("[" + uid + "]   进入聊天室");
    }

    @OnMessage//收到消息执行
    public void onMessage(String message, Session session) {
        String uid = getUid(session);
        sendMessage(uid + "  (" + DateUtils.getDate() + ")  说: " + message);
    }

    @OnClose//关闭连接执行
    public void onClose(Session session) {
        System.out.println(session.getId() + "关闭连接");
    }

    @OnError//连接错误的时候执行
    public void onError(Throwable error, Session session) {
        System.out.println("错误的时候执行");
        error.printStackTrace();
    }


    /**
     * 发送消息
     *
     * @param message
     */
    public void sendMessage(String message) {
        for (String uid : sessionMessage.keySet()) {
            try {
                sessionMessage.get(uid).getAsyncRemote().sendText(message);
            } catch (Exception e) {
            }
        }
    }


}

5.index.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>欢迎来到聊天室</title>
</head>
<body>
Welcome<br/> <span id="yhm"></span>

<div id="div1">

    <input id="account" type="text" placeholder="用户名"/>

    <button onclick="init()">连接聊天室</button>

    <hr/>
</div>

<div id="div2" hidden>
    <input id="text" type="text"/>
    <button onclick="send()">发送消息</button>
    <hr/>

</div>


<div id="message"></div>


</body>
<script type="text/javascript">
    var websocaket = null;


    function init() {
        var account = document.getElementById("account").value;
        if (account == '') {
            setdivInnerHTML("没有输入UID");
            return false;
        }


        if ('WebSocket' in window) {
            websocaket = new WebSocket("ws://110.40.210.213:8848/chat/" + account);//用于创建 WebSocket 对象。WebSocketTest对应的是java类的注解值
        } else {
            setdivInnerHTML("当前浏览器不支持");
        }
        //连接发生错误的时候回调方法;
        websocaket.onerror = function () {
            setdivInnerHTML("连接错误");
        }
        //连接成功时建立回调方法;
        websocaket.onopen = function () {

            document.getElementById("div2").hidden = false;

            document.getElementById("div1").hidden = true;
            document.getElementById("yhm").text(account);

            setdivInnerHTML("连接成功");
        }
        //收到消息的回调方法
        websocaket.onmessage = function (msg) {
            setdivInnerHTML(msg.data);
        }
        //连接关闭的回调方法
        websocaket.onclose = function () {
            setdivInnerHTML("关闭成功");
        }
    }

    //关闭websocket
    //
    function closea() {
        websocaket.close();
        alert("点击关闭");
    }

    function setdivInnerHTML(innerHTML) {
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    function send() {
        var message = document.getElementById('text').value;
        websocaket.send(message);//给后台发送数据
    }
</script>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/75803.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

jeecg-boot中实现跳过登录验证访问其他vue页面

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff0c;雄雄的小课堂。 前言 大家都知道&#xff0c;我们正常的项目&#xff0c;都做了访问限制&#xff0c;也就是&#xff0c;只有当用户登录本平台后&#xff0c;才能让用户访问别的页面&#xff0c;否则默认…

【Vue】Vue中mixins的使用方法及实际项目应用详解

文章目录&#xff08;1&#xff09;mixin基础&#xff08;2&#xff09;mixin特点1.选项合并2.方法和参数在各组件中不共享&#xff08;3&#xff09;mixin与vuex的区别&#xff08;4&#xff09;mixin与公共组件的区别&#xff08;5&#xff09;项目实践&#xff08;6&#xf…

Session | 基于Session改造oa项目的登录功能

目录 一&#xff1a;总结域对象 二&#xff1a;基于Session改造oa项目的登录功能 三&#xff1a;oa项目的安全退出系统 一&#xff1a;总结域对象 &#xff08;1&#xff09;request&#xff08;对应的类名&#xff1a;HttpServletRequest&#xff09; 请求域&#xff08;请…

【机器学习】机器学习30个笔试题

机器学习试题 在回归模型中&#xff0c;下列哪一项在权衡欠拟合&#xff08;under-fitting&#xff09;和过拟合&#xff08;over-fitting&#xff09;中影响最大&#xff1f;&#xff08;A&#xff09; A. 多项式阶数 B. 更新权重 w 时&#xff0c;使用的是矩阵求逆还是梯度下…

几款超好用的内网穿透神器,总有一款适合你!

本文以渗透的视角&#xff0c;总结几种个人常用的内网穿透&#xff0c;内网代理工具&#xff0c;介绍其简单原理和使用方法。 0x01 nps-npc 1.1 简介 nps是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持tcp、udp流量转发&#xff0c;可支持任何tcp、udp上层协…

前端js长整型精度丢失处理

一、现象 在分页查询时&#xff0c;服务端会将返回的对象进行json序列化&#xff0c;转换为json格式的数据&#xff0c;而用户的ID是一个Long类型的数据&#xff0c;而且是一个长度为 19 位的长整型数据&#xff0c; 该数据返回给前端是没有问题的。 问题实际上&#xff0c; …

适用于Unity的 Google Cardboard XR Plugin快速入门

本指南向您展示如何使用 Google Cardboard XR Plugin for Unity 创建您自己的虚拟现实 (VR) 体验。 您可以使用 Cardboard SDK 将移动设备变成 VR 平台。移动设备可以显示具有立体渲染的 3D 场景&#xff0c;跟踪头部运动并对其做出反应&#xff0c;并通过检测用户何时按下查看…

MySQL篇【5】——约束

目录表的约束空属性默认值列描述zerofill主键自增长唯一键外键如何理解外键约束在数据库的实际操作中难免会有一些操作不规范的地方&#xff0c;比方说在一张学生成绩表中&#xff0c;成绩的最高值为100&#xff0c;那么如果在这张表中如果出现了超过100分的成绩那显然是不合理…

单片机定时器

定时器 STM32有11个定时器&#xff0c;2个高级定时器、4个通用定时器&#xff0c;2个基本定时器&#xff0c;1个系统嘀嗒定时器&#xff08;systick&#xff09;&#xff0c;2个看门狗定时器。 定时器计算&#xff1a; Tout((per)psc)/Tclk t&#xff08;f/pre&#xff09;per…

Spire.Office for Java 7.12.2 迎接新年/圣诞!!!

谷歌找破解版Spire.Office for Java is a combination of Enterprise-Level Office Java APIs offered by E-iceblue. It includes Spire.Doc for Java, Spire.XLS for Java, Spire.Presentation for Java, Spire.PDF for Java and Spire.Barcode for Java.内容及配图来自网络 …

cv2.findContours() 图像的轮廓

cv2.findContours(image, mode, method, contoursNone, hierarchyNone, offsetNone)参数&#xff1a; image&#xff1a;寻找轮廓的图像&#xff0c;注意输入的图片必须为二值图片。若输入的图片为彩色图片&#xff0c;必须先进行灰度化和二值化 mode&#xff1a;轮廓的检索模…

高分子PEG: mPEG-Phosphate MV 1K 2K 3.4K 5K 10K 20K 特点分享

【中文名称】甲氧基-聚乙二醇-磷酸盐 【英文名称】 mPEG-Phosphate 【结 构 式】 【CAS号】N/A 【分子式】N/A 【MV】1000、2000、3400、5000、10000、20000 【基团部分】Phosphate PEG&#xff0c;磷酸盐PEG 【纯度标准】95% 【包装规格】1g&#xff0c;5g&#xff0c;10g&…

java基于Springboot的影视管理系统-计算机毕业设计

项目介绍 影城管理系统的主要使用者分为管理员和用户&#xff0c;实现功能包括管理员&#xff1a;首页、个人中心、用户管理、电影类型管理、放映厅管理、电影信息管理、购票统计管理、系统管理、订单管理&#xff0c;用户前台&#xff1a;首页、电影信息、电影资讯、个人中心…

acwing-Django项目——前期工作+前端js css

文章目录1.租服务器配置环境 配置docker环境创建工作用户ljh并赋予sudo权限配置免密登录方式给server1装环境装docker将AC Terminal中的/var/lib/acwing/docker/images/docker_lesson_1_0.tar镜像上传到租好的服务器中将镜像加载到本地配置docker环境创建项目配置git运行一下dj…

C++中前置操作性能一定优于后置操作?

后置操作和前置操作&#xff0c;一个会产生临时变量&#xff0c;一个不会产生临时变量&#xff0c;其原因是&#xff1a;前置操作遵循的规则是change-then-use&#xff0c;而后置操作遵循的规则是use-then-change。正因为后置操作的use-then-change原则&#xff0c;使得编译器在…

Python如何pip批量安装指定包 - 最简单方法

文章目录背景解决办法1. 制作requirements.txt文件2. 将requirements.txt传到需要部署的电脑上3. 批量安装包背景 有很多台服务器需要配置, 简单说也就是公司给我配备了3台Windows, 我需要配置Python环境并安装7个包, 如果按照常规的pip install我至少得安装3x721次, 并且得一…

data shift--学习笔记

一般假设训练集和测试集是独立同分布的&#xff0c;才能保证在训练集上表现良好的模型同样适用于测试集。当训练集和测试集不同分布时&#xff0c;就发生了dataset shiftdata shift类型&#xff1a; 协变量偏移&#xff08;covariate shift&#xff09;&#xff1a; 协变量&…

简约而不简单!分布式锁入门级实现主动续期-自省

一、背景 一个分布式锁应具备的功能特点中有避免死锁这一条&#xff1a; 如果某个客户端获得锁之后处理时间超过最大约定时间&#xff0c;或者持锁期间内发生了故障导致无法主动释放锁&#xff0c;其持有的锁也能够被其他机制正确释放&#xff0c;并保证后续其它客户端也能加锁…

Unity 3D 刚体(Rigidbody)|| Unity 3D 刚体实践案例

Unity 3D 中的 Rigidbody 可以为游戏对象赋予物理特性&#xff0c;使游戏对象在物理系统的控制下接受推力与扭力&#xff0c;从而实现现实世界中的物理学现象。 我们通常把在外力作用下&#xff0c;物体的形状和大小&#xff08;尺寸&#xff09;保持不变&#xff0c;而且内部…

Vue3 —— Pinia 的学习指南以及案例分享

文章目录 前言一、什么是pinia?二、为什么要使用Pinia?三、Pinia对比Vuex四、具体使用方法 1.安装2.创建一个store五、state 1.访问state2.重置状态3.修改state4.批量修改state5.替换state六、getters 1.访问getters2.getters传参3.写为普通函数可调用this4.访问其他的store中…