实现会议管理功能

news2025/1/31 10:59:52

目录

生成原始会议数据

一、数据结构

二、添加测试数据

查询会议列表分页数据(后端) 

一、业务分析

二、编写持久层代码

三、编辑业务层代码

四、编写Web层代码

查询成员列表(后端)

一、编写持久层代码

二、编写业务层代码

三、编写Web层代码

实现会议成员的增删

一、查询会议成员信息

部署工作流项目

一、为什么要把工作流独立成项目?

二、部署工作流项目

三、工作流BPMN

开启会议审批工作流(持久层&业务层) 

开启会议审批工作流(Web层)

保存会议记录(移动端)

加载现有会议详情

编辑会议重新发起工作流(持久层&业务层) 

编辑会议重新发起工作流(Web层&移动端)

删除会议和工作流(后端)

删除会议和工作流(移动端)


生成原始会议数据

一、数据结构

        前一个小节,我们把静态的会议列表页面做出来了,很多同学都想把其中的静态数据换成动态数据,所以咱们把后端的Java代码写一下。想要在页面上展示会议记录,那就需要读取tb_meeting 数据表,但是这个表里面并没有初始数据,所以我们来写程序生成原始会议数据。 

        首先咱们来认识一下会议表(tb_meeting),这个数据表包含了14个字段。其中的 members 字段是JSON格式,记录所有参会人员的ID。 instance_id 字段是工作流实例ID,因为会议创建出来之后,必须经过审批才能正式执行。

注意:数据表中date time类型 映射到 Java pojo包中String类型。 

二、添加测试数据

在 TbMeetingDao.xml 文件中添加INSERT语句

    <insert id="insertMeeting" parameterType="com.example.emos.wx.db.pojo.TbMeeting">
        INSERT INTO tb_meeting
        SET uuid = #{uuid},
        title = #{title},
        date = #{date},
        creator_id = #{creatorId},
        <if test="place!=null">
            place = #{place},
        </if>
        start = #{start},
        end = #{end},
        type = #{type},
        members = #{members},
        `desc` = #{desc},
        instance_id = #{instanceId},
        status = #{status},
        create_time = NOW()
    </insert>

编写 TbMeetingDao.java 接口,添加DAO方法 

@Mapper
public interface TbMeetingDao {
    public int insertMeeting(TbMeeting entity);
}

创建 MeetingService.java 接口,添加抽象方法 

public interface MeetingService { 
    public void insertMeeting(TbMeeting entity);
} 

创建 MettingServiceImpl.java 类,添加实现方法 

@Service
@Slf4j
public class MeetingServiceImpl implements MeetingService {
    @Autowired
    private TbMeetingDao meetingDao;

    @Override
    public void insertMeeting(TbMeeting entity) {
        int row = meetingDao.insertMeeting(entity);
        if (row != 1) {
            throw new EmosException("会议添加失败");
        }
        //开启审批工作流
        //startMeetingWorkflow(entity.getUuid(), entity.getCreatorId().intValue(), entity.getDate(), entity.getStart());
    }
}

在 EmosWxApiApplicationTests.java 类中,编写生成原始会议记录的代码

@SpringBootTest
class EmosWxApiApplicationTests {
    @Autowired
    private MeetingService meetingService;

    @Test
    void createMeetingData(){
        for (int i=1;i<=100;i++){
            TbMeeting meeting=new TbMeeting();
            meeting.setId((long)i);
            meeting.setUuid(IdUtil.simpleUUID());
            meeting.setTitle("测试会议"+i);
            meeting.setCreatorId(15L); //ROOT用户ID
            meeting.setDate(DateUtil.today());
            meeting.setPlace("线上会议室");
            meeting.setStart("08:30");
            meeting.setEnd("10:30");
            meeting.setType((short) 1);
            meeting.setMembers("[15,16]");
            meeting.setDesc("会议研讨Emos项目上线测试");
            meeting.setInstanceId(IdUtil.simpleUUID());
            meeting.setStatus((short)3);
            meetingService.insertMeeting(meeting);
        }
    }
}

查询会议列表分页数据(后端) 

一、业务分析

        每个员工只能看到自己参与的会议记录,自己不参与的会议是看不到的。而且会议必须是未开始状态,或者进行中状态才能被看到,已经结束的会议、审批中的会议、审批不通过的会议都是无法被看到的。

二、编写持久层代码

在 TbMeetingDao.xml 文件中编写分页查询的SQL语句

    <select id="searchMyMeetingListByPage" parameterType="HashMap" resultType="HashMap">
        SELECT
            m.id,
            m.uuid,
            m.title,
            u2.name,
            DATE_FORMAT(m.date,'%Y年%m月%d日') AS date,
            m.place,
            DATE_FORMAT(m.start,'%H:%i') AS start,
            DATE_FORMAT(m.end,'%H:%i') AS end,
            m.type,
            m.status,
            m.desc,
            u2.photo,
            TIMESTAMPDIFF(HOUR,CONCAT(m.date," ",m.start),CONCAT(m.date," ",m.end)) AS hour
        FROM tb_meeting m
        JOIN tb_user u1 ON JSON_CONTAINS(m.members,CAST(u1.id AS CHAR))
        JOIN tb_user u2 ON m.creator_id=u2.id
        WHERE u1.id = #{userId} AND u1.status = 1 AND u2.status = 1
              AND m.status IN(3,4)
        ORDER BY m.date,m.start,m.id
        LIMIT #{start}, #{length}
    </select>

在 TbMeetingDao.java 接口中定义Dao方法 

@Mapper
public interface TbMeetingDao {
    ……
    public ArrayList<HashMap> searchMyMeetingListByPage(HashMap param);
}

三、编辑业务层代码

在 MeetingService.java 中添加抽象分页方法 

public interface MeetingService { 
    ……
    public ArrayList<HashMap> searchMyMeetingListByPage(HashMap param);
} 

在 MeetingServiceImpl.java 中添加分页方法

@Service
@Slf4j
public class MeetingServiceImpl implements MeetingService {
    ……
    @Override
    public ArrayList<HashMap> searchMyMeetingListByPage(HashMap param) {
        ArrayList<HashMap> list = meetingDao.searchMyMeetingListByPage(param);
        String date = null;
        ArrayList resultList = new ArrayList();
        HashMap resultMap = null;
        JSONArray array = null;
        for (HashMap map : list) {
            String temp = map.get("date").toString();
            if (!temp.equals(date)) {
                date = temp;
                resultMap = new HashMap();
                resultMap.put("date", date);
                array = new JSONArray();
                resultMap.put("list", array);
                resultList.add(resultMap);
            }
            array.put(map);
        }
        return resultList;
    }
}

四、编写Web层代码

创建 SearchMyMeetingListByPageForm.java 封装分页请求数据 

@Data
@ApiModel
public class SearchMyMeetingListByPageForm {
    @NotNull
    @Min(1)
    private Integer page;
    @NotNull
    @Range(min = 1,max = 40)
    private Integer length;

}

创建 MeetingController.java 类,添加分页查询Web方法

@RestController
@RequestMapping("/meeting")
@Slf4j
public class MeetingController {
    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private MeetingService meetingService;

    @PostMapping("/searchMyMeetingListByPage")
    @ApiOperation("查询会议列表分页数据")
    public R searchMyMeetingListByPage(@Valid @RequestBody SearchMyMeetingListByPageForm form,@RequestHeader("token") String token){
        int userId=jwtUtil.getUserId(token);
        int page=form.getPage();
        int length=form.getLength();
        long start=(page-1)*length;
        HashMap map=new HashMap();
        map.put("userId",userId);
        map.put("start",start);
        map.put("length",length);
        ArrayList list=meetingService.searchMyMeetingListByPage(map);
        return R.ok().put("result",list);
    }
}

查询成员列表(后端)

一、编写持久层代码

在TbDeptDao.xml文件中编写SQL语句

  <select id="searchDeptMembers" parameterType="String" resultType="HashMap">
    SELECT
        d.id,
        d.dept_name AS deptName,
        COUNT(u.id) AS count
    FROM tb_dept d LEFT JOIN tb_user u ON u.dept_id=d.id AND u.status=1
    <if test="keyword!=null">
        WHERE u.name LIKE '%${keyword}%'
    </if>
    GROUP BY d.id
  </select>

在 TbDeptDao.java 接口中的DAO方法

@Mapper
public interface TbDeptDao {
    public ArrayList<HashMap> searchDeptMembers(String keyword);
}

在 TbUserDao.xml 文件中编写SQL语句

    <select id="searchUserGroupByDept" parameterType="String" resultType="HashMap">
        SELECT
        d.id AS deptId,
        d.dept_name AS deptName,
        u.id AS userId,
        u.name
        FROM tb_dept d JOIN tb_user u ON u.dept_id=d.id
        WHERE u.status=1
        <if test="keyword!=null">
            AND u.name LIKE '%${keyword}%'
        </if>
        ORDER BY d.id, u.id;
    </select>

编写 TbUserDao.java 接口中的DAO方法 

@Mapper
public interface TbUserDao {
    ……
    public ArrayList<HashMap> searchUserGroupByDept(String keyword);
}

二、编写业务层代码

在 UserService.java 中创建编写抽象方法

public interface UserService {
    ……
    public ArrayList<HashMap> searchUserGroupByDept(String keyword);
}

在 UserServiceImpl.java 中实现抽象方法

@Service
@Slf4j
@Scope("prototype")
public class UserServiceImpl implements UserService {
    ……
    @Override
    public ArrayList<HashMap> searchUserGroupByDept(String keyword) {
        ArrayList<HashMap> list_1=deptDao.searchDeptMembers(keyword);
        ArrayList<HashMap> list_2=userDao.searchUserGroupByDept(keyword);
        for(HashMap map_1:list_1){
            long deptId=(Long)map_1.get("id");
            ArrayList members=new ArrayList();
            for(HashMap map_2:list_2){
               long id=(Long) map_2.get("deptId");
               if(deptId==id){
                   members.add(map_2);
               }
            }
            map_1.put("members",members);
        }
        return list_1;
    }
}

// 数据表中 int 类型 可能映射为 Java中 Long 类型

三、编写Web层代码

创建 SearchUserGroupByDeptForm.java 类,接收移动端提交的数据

@Data
@ApiModel
public class SearchUserGroupByDeptForm {
    @Pattern(regexp = "^[\\u4e00-\\u9fa5]{1,15}$")
    private String keyword;
}

编写 UserController.java 的Web方法,接收移动端请求

@RestController
@RequestMapping("/user")
@Api("用户模块Web接口")
public class UserController {
    ……
    @PostMapping("/searchUserGroupByDept")
    @ApiOperation("查询员工列表,按照部门分组排列")
    @RequiresPermissions(value = {"ROOT","EMPLOYEE:SELECT"},logical = Logical.OR)
    public R searchUserGroupByDept(@Valid @RequestBody SearchUserGroupByDeptForm form){
        ArrayList<HashMap> list=userService.searchUserGroupByDept(form.getKeyword());
        return R.ok().put("result",list);
    }
}

实现会议成员的增删

一、查询会议成员信息

编写 TBUserDao.xml 文件中的SQL语句

    <select id="searchMembers" parameterType="list" resultType="HashMap">
        SELECT id,name,photo
        FROM tb_user
        WHERE status = 1
        AND id IN
        <foreach collection="list" item="one" separator="," open="(" close=")">
            #{one}
        </foreach>
    </select>

在 TbUserDao.java 中声明DAO方法

@Mapper
public interface TbUserDao {
    ……
    public ArrayList<HashMap> searchMembers(List param);
}

在 UserService.java 接口中声明抽象方法

public interface UserService {
    ……
    public ArrayList<HashMap> searchMembers(List param);
}

在 UserServiceImpl.java 类中实现抽象方法

@Service
@Slf4j
@Scope("prototype")
public class UserServiceImpl implements UserService {
    ……
    @Override
    public ArrayList<HashMap> searchMembers(List param) {
        ArrayList<HashMap> list=userDao.searchMembers(param);
        return list;
    }
}

创建 SearchMembersForm.java 类,接收移动端提交的数据

@Data
@ApiModel
public class SearchMembersForm {
    @NotBlank
    private String members;
}

编写 UserController.java 中的Web方法

@RestController
@RequestMapping("/user")
@Api("用户模块Web接口")
public class UserController {
    ……
    @PostMapping("/searchMembers")
    @ApiOperation("查询成员")
    @RequiresPermissions(value = {"ROOT", "MEETING:INSERT", "MEETING:UPDATE"},logical = Logical.OR)
    public R searchMembers(@Valid @RequestBody SearchMembersForm form){
        if(!JSONUtil.isJsonArray(form.getMembers())){
           throw new EmosException("members不是JSON数组");
        }
        List param=JSONUtil.parseArray(form.getMembers()).toList(Integer.class);
        ArrayList list=userService.searchMembers(param);
        return R.ok().put("result",list);
    }
}

// JSONUtil.isJsonArray()
// JSONUtil.parseArray().toList(Integer.class)
// 对应前端AJAX提交数据 {members: JSON.stringify(members)}

部署工作流项目

一、为什么要把工作流独立成项目?

        本课程的工作流部分已经剥离成独立的项目,跟emos-wx-api项目形成分布式调用关系。为什么要把工作流独立出来有三点考虑:

  1. 最新的Activiti7工作流引擎需要JDK1.8以上的环境,很多同学的JDK都还是1,8的,所以独立出来可以单独部署在高版本JDK的Docker容器里面,并不影响emos-wx-api项目。
  2. 因为工作流引擎搭建和BPMN绘制较为麻烦,所以方便大家使用,我就把该部分内容打成JAR文件了,直接部署就可以使用工作流引擎。
  3. 独立出来的工作流项目部署在其他的主机上面,容易获得更好的性能。如果所有的功能都整合到一个项目中,运行的时候主机压力较高,而且无法分拆。

二、部署工作流项目

大家在GIT 项目上面下载 jdk.tar.gz 镜像文件,把该镜像上传到centos系统,导入Docker环境

docker load < jdk.tar.gz

然后执行命令,创建JDK容器

docker run -it -d --name=workflow -p 9090:9090 -v /root/workflow:/root/workflow jdk

在Navicat上面上面执行 工作流.sql 文件,导入工作流依赖的各种数据表

        用好压软件(推荐此款压缩软件)打开 emos-workflow.jar文件。找到application.yml 文件,点击右键,选择用内部查看器打开。修改其中的MYSQL连接信息和Redis连接信息,并且保存该文件。好压软件会弹出对话框是否更新该压缩文件,选择确定。

        把 emos-workflow. jar 文件上传到Linux的 /root/workflow 文件夹,然后进入到Docker容器,运行工作流程序

// 注意先配置好 java 和 nohup 环境变量

docker exec -it workflow bash

cd /root/workflow

nohup java -jar emos-workflow.jar >> out.log 2>&1 &

三、工作流BPMN

        会议审批流程如上图,因为无论审批结果是什么,都要向emos-wx-api 项目发送HTTP请求,告知审批结果。

  1. 如果创建会议的是总经理,那么不需要审批,该会议直接通过;如果创建会议的不是总经理,那么必须要经过审批。
  2. 如果参会人都不是同一个部门的,需要先由发起人所在部门的经理审批,然后由总经理审批;如果参会人都是一个部门的,那就只需要该部门的经理审批即可。

开启会议审批工作流(持久层&业务层) 

  <select id="searchUserInfo" parameterType="int" resultType="HashMap">
    SELECT
      u.open_id AS openId,
      u.nickname,
      u.name,
      u.photo,
      u.sex,
      u.tel,
      u.email,
      d.dept_name AS dept,
      u.hiredate,
      CASE u.status
        WHEN 1 THEN "在职"
        WHEN 2 THEN "离职"
        END AS status,
      ( SELECT GROUP_CONCAT( role_name separator "," ) FROM tb_role WHERE JSON_CONTAINS ( u.role, CONVERT ( id, CHAR ) ) ) AS roles
    FROM tb_user u
           LEFT JOIN tb_dept d ON u.dept_id = d.id
    WHERE u.id = #{userId} AND u.status = 1
  </select>
  <select id="searchDeptManagerId" parameterType="int" resultType="int">
    SELECT
      u2.id
    FROM tb_user u1 JOIN tb_user u2 ON u1.dept_id=u2.dept_id
                    JOIN tb_role r ON JSON_CONTAINS(u2.role, CAST(r.id AS CHAR))
    WHERE u1.id=#{id} AND r.id=2 AND u1.status = 1 AND u2.status = 1
  </select>

  <select id="searchGmId" resultType="int">
    SELECT
      u.id
    FROM tb_user u
           JOIN tb_role r ON JSON_CONTAINS(u.role, CAST(r.id AS CHAR))
    WHERE r.id=1 AND u.status = 1
  </select>
  <select id="searchMeetingMembersInSameDept" parameterType="String" resultType="boolean">
    SELECT
      IF(COUNT(DISTINCT u.dept_id)=1,TRUE,FALSE ) AS bool
    FROM tb_meeting m
           JOIN tb_user u ON JSON_CONTAINS ( m.members, CAST( u.id AS CHAR ) )
    WHERE m.uuid=#{uuid} AND u.status = 1
  </select>
    private void startMeetingWorkflow(String uuid, int creatorId, String date, String start) {
        HashMap info = userDao.searchUserInfo(creatorId);
        JSONObject json = new JSONObject();
        json.set("url", recieveNotify);
        json.set("uuid", uuid);
        json.set("openId", info.get("openId"));
        json.set("code", code);
        json.set("date", date);
        json.set("start", start);
        String[] roles = info.get("roles").toString().split(",");
        if (!ArrayUtil.contains(roles, "总经理")) {
            Integer managerId = userDao.searchDeptManagerId(creatorId);
            json.set("managerId", managerId);
            Integer gmId = userDao.searchGmId();
            json.set("gmId", gmId);
            boolean bool = meetingDao.searchMeetingMembersInSameDept(uuid);
            json.set("sameDept", bool);
        }
        String url = workflow + "/workflow/startMeetingProcess";
        HttpResponse resp = HttpRequest.post(url).header("Content-Type", "application/json")
                .body(json.toString()).execute();
        if (resp.getStatus() == 200) {
            json = JSONUtil.parseObj(resp.body());
            String instanceId = json.getStr("instanceId");
            HashMap param = new HashMap();
            param.put("uuid", uuid);
            param.put("instanceId", instanceId);
            int row = meetingDao.updateMeetingInstanceId(param);
            if (row != 1) {
                throw new EmosException("保存会议工作流实例ID失败");
            }
        }
    }

开启会议审批工作流(Web层)

@Data
@ApiModel
public class InsertMeetingForm {
    @NotBlank
    private String title;
    @NotNull
    @Pattern(regexp = "^((((1[6-9]|[2-9]\\d)\\d{2})-(0?[13578]|1[02])-(0?[1-9]|[12]\\d|3[01]))|(((1[6-9]|[2-9]\\d)\\d{2})-(0?[13456789]|1[012])-(0?[1-9]|[12]\\d|30))|(((1[6-9]|[2-9]\\d)\\d{2})-0?2-(0?[1-9]|1\\d|2[0-8]))|(((1[6-9]|[2-9]\\d)(0[48]|[2468][048]|[13579][26])|((16|[2468][048]|[3579][26])00))-0?2-29-))$")
    private String date;
    private String place;
    @NotNull
    @Pattern(regexp = "^([01]?[0-9]|2[0-3]):[0-5][0-9]$")
    private String start;
    @NotNull
    @Pattern(regexp = "^([01]?[0-9]|2[0-3]):[0-5][0-9]$")
    private String end;

    @Range(min = 1,max = 2)
    private Byte type;

    @NotBlank
    private String members;
    @NotBlank
    private String desc;

}
    @PostMapping("/insertMeeting")
    @ApiOperation("添加会议")
    @RequiresPermissions(value = {"ROOT", "MEETING:INSERT"},logical = Logical.OR)
    public R insertMeeting(@Valid @RequestBody InsertMeetingForm form, @RequestHeader("token") String token){
        if(form.getType()==2&&(form.getPlace()==null||form.getPlace().length()==0)){
            throw new EmosException("线下会议地点不能为空");
        }
        DateTime d1= DateUtil.parse(form.getDate()+" "+form.getStart()+":00");
        DateTime d2= DateUtil.parse(form.getDate()+" "+form.getEnd()+":00");
        if(d2.isBeforeOrEquals(d1)){
            throw new EmosException("结束时间必须大于开始时间");
        }
        if(!JSONUtil.isJsonArray(form.getMembers())){
            throw new EmosException("members不是JSON数组");
        }
        TbMeeting entity=new TbMeeting();
        entity.setUuid(UUID.randomUUID().toString(true));
        entity.setTitle(form.getTitle());
        entity.setCreatorId((long)jwtUtil.getUserId(token));
        entity.setDate(form.getDate());
        entity.setPlace(form.getPlace());
        entity.setStart(form.getStart() + ":00");
        entity.setEnd(form.getEnd() + ":00");
        entity.setType((short)form.getType());
        entity.setMembers(form.getMembers());
        entity.setDesc(form.getDesc());
        entity.setStatus((short)1);
        meetingService.insertMeeting(entity);
        return R.ok().put("result","success");
    }

保存会议记录(移动端)

JwtUtil int > entity long > dao int > 数据表 int

前端JSON.stringify > entity Object > dao Object > 数据表 json

加载现有会议详情

  <select id="searchMeetingById" parameterType="int" resultType="HashMap">
    SELECT
      m.uuid,
      m.creator_id AS creatorId,
      m.title,
      u.name,
      DATE_FORMAT( m.date, '%Y-%m-%d' ) AS date,
            m.place,
            DATE_FORMAT( m.START, '%H:%i' ) AS start,
      DATE_FORMAT( m.END, '%H:%i' ) AS end,
            m.type,
            m.status,
            m.desc,
            m.instance_id AS instanceId
        FROM tb_meeting m
        JOIN tb_user u ON m.creator_id = u.id
        WHERE m.id =#{id} AND u.status = 1
  </select>
  <select id="searchMeetingMembers" parameterType="int" resultType="HashMap">
    SELECT
      u.id,
      u.name,
      u.photo
    FROM tb_meeting m
           JOIN tb_user u ON JSON_CONTAINS ( m.members, CAST( u.id AS CHAR ) )
    WHERE m.id=#{id} AND u.status = 1
  </select>

编辑会议重新发起工作流(持久层&业务层) 

    @Override
    public void updateMeetingInfo(HashMap param) {
        int id = (int) param.get("id");
        String date = param.get("date").toString();
        String start = param.get("start").toString();
        String instanceId = param.get("instanceId").toString();

        HashMap oldMeeting = meetingDao.searchMeetingById(id);
        String uuid = oldMeeting.get("uuid").toString();

        Integer creatorId = Integer.parseInt(oldMeeting.get("creatorId").toString());

        int row = meetingDao.updateMeetingInfo(param);
        if (row != 1) {
            throw new EmosException("会议更新失败");
        }

        JSONObject json = new JSONObject();
        json.set("instanceId", instanceId);
        json.set("reason", "会议被修改");
        json.set("uuid", uuid);
        json.set("code", code);
        String url = workflow + "/workflow/deleteProcessById";
        HttpResponse resp = HttpRequest.post(url).header("content-type", "application/json")
                .body(json.toString()).execute();
        if (resp.getStatus() != 200) {
            log.error("删除工作流失败");
            throw new EmosException("删除工作流失败");
        }

        startMeetingWorkflow(uuid, creatorId, date, start);
    }

编辑会议重新发起工作流(Web层&移动端)

        ……

删除会议和工作流(后端)

DateTime date = DateUtil.parse(meeting.get("date") + " " + meeting.get("start"));
DateTime now = DateUtil.date();
if (now.isAfterOrEquals(date.offset(DateField.MINUTE, -20))) {
    throw new EmosException("距离会议开始不足20分钟,不能删除会议");
}
int row = meetingDao.deleteMeetingById(id);
if (row != 1) {
    throw new EmosException("会议删除失败");
}

  UUID 在线会议房间号。

删除会议和工作流(移动端)

        ……

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

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

相关文章

Mybatis-plus——查询条件设置+字段映射和表名映射

查询条件设置 等匹配查询 假如要进行登录查询的话&#xff0c;需要用到如下的等匹配&#xff0c;在实际的登录中应该做md5加密&#xff0c;从查询条件取出密码。 //条件查询LambdaQueryWrapper<mpdb> lqwnew LambdaQueryWrapper<mpdb>();//模拟登陆查询等匹配lqw…

SELF-ATTENTION DOES NOT NEED O(n2) MEMORY

背景 主要是要解决self-attention空间复杂度的问题&#xff0c;因为对于gpu计算来说&#xff0c;内存空间非常宝贵&#xff0c;序列长度较长的时候会出现oom问题。 用线性时间解决self-attention问题 解决数据稳定问题 因为由于进行求和计算&#xff0c;容易导致浮点数超过最…

栈区和堆区以及注意事项

>>栈区 #include<stdio.h> #include<string.h> #include<stdlib.h>int* func() {int a 10;//栈上创建的变量return &a; }void test01() {int* p func();//结果早已不重要&#xff0c;因为上面的a早已被释放&#xff0c;再去操作这块内存属于//非…

行业追踪,2023-07-04,受特斯拉中报影响,汽车零部件放量强势拉升,不调整

自动复盘 2023-07-04 成交额超过 100 亿 排名靠前&#xff0c;macd柱由绿转红 成交量要大于均线 有必要给每个行业加一个上级的归类&#xff0c;这样更能体现主流方向 rps 有时候比较滞后&#xff0c;但不少是欲杨先抑&#xff0c; 应该持续跟踪&#xff0c;等 macd 反转时参与…

Gitbash常用指令总结

Part I git 开始的指令 1、git init&#xff1a;初始化一个Git仓库&#xff1b; 2、git clone&#xff1a;从远程仓库克隆代码到本地&#xff1b; 直接使用网址 git clone <url>or 用a代替网址 git remote add a <url>git clone a3、git add&#xff1a;添加文件到…

计算机基础--->数据结构(8)【B树、B+树<超详细图文>】

文章目录 B树(B-Tree)B树的查询操作B树的几种插入删除情况 B树B树的主要特点插入操作删除操作 B树(B-Tree) B树&#xff08;B-Tree&#xff09;是一种自平衡的搜索树&#xff0c;又称平衡多路查找树&#xff0c;主要用于系统中大量数据的读和写操作。B树的特点是能保持数据有序…

English-英语语法体系

语法体系 英语中的所有语句类型&#xff1a;什么怎么样 英语语法最重要的就是动词&#xff01;

3.4.流的学习,异步任务的管理

目录 前言1. 流总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习精简 CUDA 教程-流的学习&#xff0c;异步任务的管理 课程大…

MySQL库表操作作业

创建数据库 mysql> create database Market; mysql> use Market; 创建表和约束 mysql> create table customers(c_num int(11) primary key not null UNIQUE Key auto_increment , -> c_name varchar(50), -> c_city varchar(50), -> c_birth datetime…

九、HTML中的定位

1、定位 position static 默认值 没有使用定位 relactive 相对定位 absolute 绝对定位 fixed 锚定 标准文档流 标准文档流 从上到下&#xff0c;从左向右&#xff0c;依次显示网页中的每一个元素 元素分类 行内元素 依次一个挨着一个显示 块级元素 独占一行 static 定位 以…

【STM32智能车】智能寻迹

【STM32智能车】智能寻迹 基础算法寻迹小车 我们之前说了到了寻迹这里会涉及到一些算法&#xff0c;不过各位小伙伴可以放心&#xff0c;我们这里用的是一些基础算法。不需要公式&#xff0c;只需要进行简单的判断就行。 基础算法 寻迹车的程序算法如下&#xff1a; 初始化&…

MySQL数据库小练习1

1.创建数据库&#xff0c;删除数据库&#xff0c;查询创建数据的语句&#xff0c;使用数据库&#xff0c;查询当前默认的数据库以及使用的编码方式校验规则 创建数据库及使用数据库&#xff1a; create database hzc default character set utf8mb4 collate utf8mb4_0900_ai_…

uniapp电子签名以及竖屏签名后内容旋转90度变为横屏图片

用该插件挺不错的 电子签名插件地址 如果你一个页面要用多个该插件&#xff0c;就改成不同的cavas-id&#xff0c;修改插件源码 效果图 竖屏写 旋转成横屏图片 插件内 在拿到签名临时地址后的页面 <!-- 旋转图片canvas --> <canvas canvas-id"camCacnvs&quo…

第二次CCF计算机软件能力认证

第一题&#xff1a;相邻数对 给定 n 个不同的整数&#xff0c;问这些数中有多少对整数&#xff0c;它们的值正好相差 1。 输出格式 输入的第一行包含一个整数 n&#xff0c;表示给定整数的个数。 第二行包含所给定的 n 个整数。 输出格式 输出一个整数&#xff0c;表示值正好相…

华为OD计算工时python脚本

前言 刚入职不知道工时要平均每天满8小时&#xff0c;并且看不到每天的实际工时&#xff0c;一气之下花了一个中午写了个脚本计算每天的工时&#xff0c;分享一下&#xff0c;不同地区的兄弟需要修改一下午休和晚饭时间才能使用。 文件位置 把welink上 上下班时间输入work.c…

支持向量机推导之r||w||=1的限制转化

支持向量机推导之r||w||1的限制转化 很多同学肯定是学过支持向量机的&#xff0c;也可能大致的理解了支持向量机这个算法&#xff0c;我想大部分人在学习这个算法的时候&#xff0c;对于推导过程有一步应该是不太理解。 我先简要介绍一下SVM,SVM的核心思想在于找到一个多维空间…

getCurrentInstance

https://blog.csdn.net/m0_46318298/article/details/130726043 注&#xff1a;$是在vue中所有实例中都可用的一个简单约定&#xff0c;这样做会避免和已被定义的数据&#xff0c;方法&#xff0c;计算属性产生冲突。

Leetcode-每日一题【203.移除链表元素】

题目 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6输出&#xff1a;[1,2,3,4,5] 示例 2&#xff1a; 输入&#…

nginx白名单配置

在有得项目中&#xff0c;我们会希望端口只有特定的用户可以访问&#xff0c;这时候就需要配置nginx的白名单&#xff0c;接来下展示一下白名单的配置和应用 vi /etc/nginx/nginx.conf server {listen 80;listen [::]:80;server_name _;root /usr/share/…

springboot第29集:springboot项目详细

public static LoginUser getLoginUser()&#xff1a;该行声明了一个公共的静态方法 getLoginUser()&#xff0c;它的返回类型是 LoginUser。try&#xff1a;开始一个 try 块&#xff0c;用于处理接下来的代码中可能发生的异常。return (LoginUser) getAuthentication().getPri…