webSocket 即时通讯,服务端springBoot 实现(1)

服务端实现

第一步springboot底层帮我们自动配置了websokcet,需要引入以下maven依赖

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

第二步:如果使用springboot内置容器启动项目的,需要配置Bean。如果使用其他外部的容器,则可以不需要配置 

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * 开启WebSocket支持
 * @author yann
 */
@Configuration 
public class WebSocketConfig {
    @Bean  
    public ServerEndpointExporter serverEndpointExporter() {  
        return new ServerEndpointExporter();  
    } 
}

第三步:服务端核心代码

import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Component;


@ServerEndpoint("/webSocketServer/{userId}")
@Component
public class WebSocketServer {
    /**静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。*/
    private static int onlineCount = 0;
    /**concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。*/
    private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
    /**与某个客户端的连接会话,需要通过它来给客户端发送数据*/
    private Session session;
    /**接收userId*/
    private String userId="";

    /**
     * 连接建立成功调用的方法*/
    @OnOpen
    public void onOpen(Session session,@PathParam("userId") String userId) {
        this.session = session;
        this.userId=userId;
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            webSocketMap.put(userId,this);
            //加入set中
        }else{
            webSocketMap.put(userId,this);
            //加入set中
            addOnlineCount();
            //在线数加1
        }
        //System.out.println("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
        try {
            sendMessage("连接成功");
        } catch (IOException e) {
            //System.out.println("用户:"+userId+",网络异常!!!!!!");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            //从set中删除
            subOnlineCount();
        }
        //System.out.println("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息*/
    @OnMessage
    public void onMessage(String message, Session session) {
        //System.out.println("用户消息:"+userId+",报文:"+message);
        //可以群发消息
        //消息保存到数据库、redis
        if(StringUtils.isNotBlank(message)){
            try {
                //解析发送的报文
                JSONObject jsonObject = JSON.parseObject(message);
                //追加发送人(防止串改)
                jsonObject.put("fromUserId",this.userId);
                String toUserId=jsonObject.getString("toUserId");
                //传送给对应toUserId用户的websocket
                if(StringUtils.isNotBlank(toUserId)&&webSocketMap.containsKey(toUserId)){
                    webSocketMap.get(toUserId).sendMessage(jsonObject.toJSONString());
                }else{
                    //System.out.println("请求的userId:"+toUserId+"不在该服务器上");
                    //否则不在这个服务器上,发送到mysql或者redis
                }
            }catch (Exception e){
               // e.printStackTrace();
            }
        }
    }

    /**
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        //System.out.println("用户错误:"+this.userId+",原因:"+error.getMessage());
        //error.printStackTrace();
    }
    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }


    /**
     * 发送自定义消息
     * */
    public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
        //System.out.println("发送消息到:"+userId+",报文:"+message);
        if(StringUtils.isNotBlank(userId)&&webSocketMap.containsKey(userId)){
            webSocketMap.get(userId).sendMessage(message);
        }else{
            //System.out.println("用户"+userId+",不在线!");
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

}

 

第四步:前端调用WebSocketController 

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.inet.templogs.app.common.webSocket.WebSocketServer;

import java.io.IOException;

/**
 * WebSocketController
 * @author yann
 */
@RestController
@RequestMapping(value="/webSocket",produces={"application/json;charset=UTF-8"})
public class WebSocketController {

	    @RequestMapping("/push/{toUserId}")
	    public ResponseEntity<String> pushToWeb(String message, @PathVariable String toUserId) throws IOException {
	        WebSocketServer.sendInfo(message,toUserId);
	        return ResponseEntity.ok("MSG SEND SUCCESS");
	    }
}

第五步:前端html代码示例

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>websocket通讯</title>
</head>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
    var socket;
    function openSocket() {
        if(typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        }else{
            console.log("您的浏览器支持WebSocket");
            //实现化WebSocket对象,指定要连接的服务器地址与端口  建立连接
            //等同于socket = new WebSocket("ws://localhost:8888/xxxx/im/25");
            //var socketUrl="${request.contextPath}/im/"+$("#userId").val();
            //var    
 socketUrl="http://localhost:9101/webSocketServer/"+$("#userId").val();
			var socketUrl="	
            socketUrl=socketUrl.replace("https","wss").replace("http","ws");
            console.log(socketUrl);
            if(socket!=null){
                socket.close();
                socket=null;
            }
            socket = new WebSocket(socketUrl);
            //打开事件
            socket.onopen = function() {
                console.log("websocket已打开");
                //socket.send("这是来自客户端的消息" + location.href + new Date());
            };
            //获得消息事件
            socket.onmessage = function(msg) {
                console.log(msg.data);
                //发现消息进入    开始处理前端触发逻辑
            };
            //关闭事件
            socket.onclose = function() {
                console.log("websocket已关闭");
            };
            //发生了错误事件
            socket.onerror = function() {
                console.log("websocket发生了错误");
            }
        }
    }
    function sendMessage() {
        if(typeof(WebSocket) == "undefined") {
            console.log("您的浏览器不支持WebSocket");
        }else {
            console.log("您的浏览器支持WebSocket");
            console.log('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
            socket.send('{"toUserId":"'+$("#toUserId").val()+'","contentText":"'+$("#contentText").val()+'"}');
        }
    }
</script>
<body>
<p>【userId】:<div><input id="userId" name="userId" type="text" value="10"></div>
<p>【toUserId】:<div><input id="toUserId" name="toUserId" type="text" value="20"></div>
<p>【toUserId】:<div><input id="contentText" name="contentText" type="text" value="hello websocket"></div>
<p>【操作】:<div><a onclick="openSocket()">开启socket</a></div>
<p>【操作】:<div><a onclick="sendMessage()">发送消息</a></div>
</body>

</html>

至此,已经全部完成

参考链接:https://blog.youkuaiyun.com/weixin_38111957/article/details/86352677 

 

 

※※※※一、特色 1、EXCEL平台 本作品采用EXCEL 公式+VBA制作,既可根据你平时使用EXCEL的习惯和方式操作充分发挥EXCEL的功能,又能利用本作品提高效率。 2、结构紧凑,界面简洁 本作品仅有三四个工作表,分别是总表、表册、设置。你可以先在总表输入、导入、复制粘贴或在记录单逐条录入原始成绩,经设置表简单设置后即可在“表册”中根据你的需要自动生成各种表册,包括分班成绩册等各种表册、成绩单、各种统计表等。 ※※※※二、与众不同 1、限制条件少,通用性强 只需把原始成绩输入、导入、复制粘贴或在记录单逐条录入总表即可,对总表要求极为宽松:不必整理试卷、非顺序录入;各列(包括科目)名称、位置任意;不受班级、每班人数、科目等数量限制,行列不受限制。简言之,只要您原始成绩表是什么样,把它搞过来就行,只需注意本总表第一行为表格项目且有班级一列和不合并单元格即可,其它不受任何限制。 2、具有容错能力 也许您对函数和公式比较熟悉,知道当公式引用的单元格被移动或删除时公式往往会出错。本作品避免了这个问题。本作品成绩册、统计表和成绩单采用公式生成,数据均来源于总表。可是对总表您尽可放心大胆编辑、修改,对数据进行各种处理,比如可以进行排序、筛选、删除等操作,哪怕移动和删除任何一行、一列,删除任何一个单元格也无妨。 3、具有恢复能力 本作品对成绩册和成绩单,虽然采用函数和公式实现,但您仍可自由编辑排版以便输出,如编辑、修改、删除公式,删除行列,哪怕删除或者清空整张表也可,如果你进行了以上或者其他误操作,您只需重新点击相应按钮即可。 ※※※※三、主要功能 1、查询:查询条件多样,可按姓名查询、按班级查询(分班);按某学科(含总分)某分数段查询;按班内名次(年级名次)段查询(如某班前XX名、年级前XX-XX名)等,各种查询条件还可自由组合。对查询结果,可按某关键字排序后显示,如按班级排名升序可组合出某班全部或班前XX名、年级前XX名排名等,按年级排名升序可组合出年级前XX名排名或全部排名等。 2、统计:根据班级和科目(含总体)按统计范围自动实时生成各项指标(参考人数、平均分、及格人数、及格率、优生人数、优生率、差生人数、差生率等)、各分数段人数统计、年级前XX名在各班分布等。 3、成绩册和成绩条:实时自动按班生成成绩册和成绩条。 ※※※※三、操作指南 在总表中输入、导入、复制粘贴或在记录单逐条录入原始成绩,经设置表简单设置后即可在“表册”中根据你的需要自动生成各种表册,包括分班成绩册等各种表册、成绩单、各种统计表等。 其中,分班成绩册和成绩单、统计分别以VBA和公式两种方式制作,这两种方式各有特点,供你选择:公式方式的优点是当条件变化(如所选班级、科目变化)时显示结果随之实时变化,除非公式被破坏或者刚从其它表册转入本功能你才需要重新点击按钮;VBA方式每次改变条件后必须点击相应按钮才能刷新结果,但对结果你可随意进行各种操作。如果你觉得窗体有可能遮住结果,窗体可移动,可关闭,也可随时按CTRL+Q(W)打开,以便在EXCEL中按你熟悉的方式操作。另总表中还提供了按班级排序、填入总分、平均分、计算班级排名、年级排名、分数超限检查等多种自动化功能。
简易成绩分析系统使用说明 四川省泸州市纳溪区大渡中学教务室制作使用 ※※※※一、特色 EXCEL平台 本作品采用EXCEL 公式+VBA制作,既可根据你平时使用EXCEL的习惯和方式操作充分发挥EXCEL的功能,又能利用本作品提高效率。 结构紧凑,界面简洁 本作品工作表个数极少,分别是总表、表册、设置。你可以先在总表输入、在记录单逐条录入、导入或复制粘贴原始成绩,经设置表简单设置后即可在“表册”中根据你的需要自动生成各种表册,包括分班成绩册等各种表册、成绩单、各种统计表等。 ※※※※二、与众不同 本人曾上网搜索到EXCEL平台成绩管理系统不下20款,发现绝大多数都或多或少存在以下问题:总表(或成绩录入表)各项目名称、位置、格式均固定,如班级只能在某列输入且各班级名称必须采用统一格式(如“七(1)”、“七(2)”等)、各科目名称、顺序、录入范围固定等;如果采用公式制作的话,有些单元格还不能移除、拖动、删除等,否则公式会发生错误,当然一不小心公式被删除或破坏那就更糟了。但本作品为你解决了这几个问题,与众不同: 1、限制条件少,通用性更强 只需把原始成绩输入、导入、复制粘贴或在记录单逐条录入总表即可,对总表要求极为宽松:不必整理试卷、非顺序录入;各列(包括科目)名称、位置任意;不受班级、每班人数、科目等数量限制,行列不受限制。简言之,只要您原始成绩表是什么样,把它搞过来就行,只是需注意对本总表的惟一要求是:第一行为表格项目且有班级一列和不合并单元格即可,其它不受任何限制。 2、具有容错能力 也许您对函数和公式比较熟悉,知道当公式引用的单元格被移动或删除时公式往往会出错。本作品避免了这个问题。本作品“成绩册(公式)”、统计表和“成绩单(公式)”采用公式生成,数据均来源于总表。可是对总表您尽可放心大胆编辑、修改,对数据进行各种处理,比如可以进行排序、筛选、删除等操作,哪怕移动和删除任何一行、一列,删除任何一个单元格也无妨。 3、具有恢复能力 本作品对“成绩册(公式)”和“成绩单(公式)”,虽然采用函数和公式实现,但您仍可自由编辑排版以便输出,如编辑、修改、删除公式,删除行列,哪怕删除或者清空整张表也可,如果你进行了以上或者其他误操作,您只需重新点击相应按钮即可自动恢复。 ※※※※三、主要功能 1、查询:查询条件多样,可按姓名查询、按班级查询(分班);按某学科(含总分)某分数段查询;按班内名次(年级名次)段查询(如某班前XX名、年级前XX-XX名)等,各种查询条件还可自由组合。对查询结果,可按某关键字排序后显示,如按班级排名升序可组合出某班全部或班前XX名、年级前XX名排名等,按年级排名升序可组合出年级前XX名排名或全部排名等。 2、统计:根据班级和科目(含总体)按统计范围自动实时生成各项指标(参考人数、平均分、及格人数、及格率、优生人数、优生率、差生人数、差生率、优质分等)、各分数段人数统计、年级前XX名在各班分布等。 3、成绩册和成绩条:自动按班生成成绩册和成绩条。 ※※※※四、操作指南 在总表中输入、导入、复制粘贴或在记录单逐条录入原始成绩,经设置表简单设置后即可在“表册”中根据你的需要自动生成各种表册,包括分班成绩册等各种表册、成绩单、各种统计表等。 其中,分班成绩册和成绩单、统计分别以VBA和公式两种方式制作,这两种方式各有特点,供你选择:公式方式的优点是当条件变化(如所选班级、科目变化)时显示结果随之实时变化,除非公式被破坏或者刚从其它表册转入本功能你才需要重新点击按钮;VBA方式每次改变条件后必须点击相应按钮才能刷新结果,但对结果你可随意进行各种操作。如果你觉得窗体有可能遮住结果,窗体可移动,可关闭,也可随时按CTRL+Q(W)打开,以便在EXCEL中按你熟悉的方式操作。另总表中还提供了按班级排序、填入总分、平均分、计算班级排名、年级排名、分数超限检查等多种自动化功能。 ※※※※四、温馨提示 1、本成绩分析设计是本人想当然而成,加之时间仓促,错误和疏漏在所难免,如果你在使用中不符合您的需要,请及时告知,以便进一步改进! 2、本成绩分析工作表之间,相互引用,相互关联,不得随意更改删除,也不得对工作表重命名,否则将影响本成绩分析的正常使用。 3、操作前请做好数据备份,凡因使用本成绩分析而造成的数据损失,本人概不负责。 4、如果不能运行宏,请把“工具--宏--安全性”中,安全级别设为“中”。 制作:石明富 2009-6-29 简易成绩分析系统使用说明 总表操作提示 进入总表,你会发现一个窗口,如图所示,你可以利用这个窗口上的按钮来自动完成某些功能,当然你也可以移动或关闭该窗口,直接在总表中进行你能够进行的各种操作,如果你关闭了该窗口,按CTRL+W还可重新显示。 对总表要求极为宽松,你只需把原始成绩输入、导入、复制粘贴或在记录单逐条录入总表即可:不必整理试卷、非顺序录入;各列(包括科目)名称、位置任意;不受班级、每班人数、科目等数量限制,行列不受限制,你看图中工作表是不是显得多么乱啊!。而且在总表中可放心大胆编辑、修改,对数据进行各种处理,比如可以进行排序、筛选、删除等操作,哪怕移动和删除任何一行、一列,删除任何一个单元格也无妨。操作时可以利用窗口中的按钮进行自动处理,你也可以在工作表中按你平时使用方式直接操作,只是需注意对本总表的惟一要求是:第一行为表格项目且有班级一列和不合并单元格即可,其它不受任何限制。 窗口中各按钮作用和功能分别简述如下: “导入”按钮:如果你有现成原始成绩数据表,可点导入选择你的原始成绩工作簿和工作表(默认为1)追加或导入数据到总表,如果追加,你的原始工作表第二行为标题且须与总表首行标题完全一致方可。 “记录单”按钮:你可以在记录单中对某条成绩记录进行查询、修改、删除、添加等。 “生成总分和平均分”按钮:按你在设置表中“C”列的科目加计总分并根据你的选择是否计算平均分。 “生成班级名次”按钮:计算该生在班内的名次,该工作表无需按班级排序,如果该总表首行无“班内名次”一列(无论在哪列),则将在该表最后一列后面自动添加“班内名次”一列并填入相应数据。 “生成年级名次”按钮:计算全校名次,效果同“生成班级名次”。 “按班排序”按钮:按班级排序,不论“班级”在哪一列。 “超限检查”按钮:按设置表“C”列科目、“D”列分值检查总表成绩是否超过上限并提示。 “添表头”按钮:按需要添加表头。 “去表头”按钮:去表头,如果首行含有“班级”一格,则视为表格项目,不能再删除。如果你需要进行统计、查询、成绩册、成绩单等操作,必须去掉表头,让首行成为表格项目。 “关闭”按钮:隐藏本窗口,需要时可按CTRL+W重新显示。 设置操作提示 进入设置,首先会询问你是否采用公式,你可以选择“否”,稍后点按钮自动输入,进入设置后,界面如图所示。 各项设置的作用和目的如下: “A” 、“B”列分别为班级选项和字段,其数据分别来源于总表“班级”一列和首行,作用是其内容将呈现在表册窗口和统计表的选项框中以便选择输入,该设置可自动生成。 “C”列为科目选项,其数据应来源于该设置“B”列,作用一是其内容将呈现在表册窗口和统计表的选项框中以便选择输入科目,二是总表中自动生成总分时将以其内容加计而成。 “D”列为“C”列各科目相应的总分,其作用一是成绩统计(公式)时各优生数、及格数、后进生数将自动分别以其相应总分的80%、60%、40%作为判断分值计算,二是总表里“超限检查”时将按此分数检查相应科目成绩是否超过上限。 “E”列作用是其内容将呈现在表册窗口的查询条件选框中以便选择输入。 “G2”、“G3”、“G4”、“G5”为计算优质分(又叫考核分、积分等)时各率加权求和的权重。 “I1”为考试名称,总表、成绩册等表头将参考其内容。 表册操作提示 进入表册,界面如下,你在本窗口中的操作不同,该工作表呈现的内容也会即时变化,分班成绩册、成绩单、多条件查询等均在该表操作,所以该表暂以“表册”命名,如果你觉得不恰当,可联系作者修改。 本表窗口中,分班成绩册和成绩单、统计分别以VBA和公式两种方式制作,这两种方式各有特点,供你选择:公式方式的优点是当条件变化(如所选班级、科目变化)时显示结果随之实时变化,除非公式被破坏或者刚从其它表册转入本功能你才需要重新点击按钮;VBA方式每次改变条件后必须点击相应按钮才能刷新结果,但对结果你可随意进行各种操作。如果选框有误,请检查设置表中相应设置是否正确。如果你觉得窗体有可能遮住结果,窗体可移动,可关闭,也可随时按CTRL+Q(W)打开,以便在EXCEL中按你熟悉的方式操作。 多条件查询为按照你设置的条件并按你要求的顺序显示相应查询结果,可按姓名查询、按班级查询(分班);按某学科(含总分)某分数段查询;按班内名次(年级名次)段查询(如某班前XX名、年级前XX-XX名)等,各种查询条件还可自由组合。对查询结果,可按某关键字排序后显示,如按班级排名升序可组合出某班全部或班前XX名、年级前XX名排名等,按年级排名升序可组合出年级前XX名排名或全部排名等。如下面窗口内设置为班级为“4”班、数学b卷大于36分的班内名次前9名同学的成绩册并按总分降序显示。 统计操作提示 进入统计表,页面如下: 根据班级和科目(含总体)按统计范围自动实时生成各项指标(参考人数、平均分、及格人数、及格率、优生人数、优生率、差生人数、差生率等)、各分数段人数统计、年级前XX名在各班分布等。 统计范围为选择全部成绩进入统计、按每班前XX名还是按全年级前XX名进行统计。 表格内班级和科目两列可点下拉框选择输入并自由组合,如班级选择不同班级,科目为同一科,则是该科成绩在各班之间的对比;如科目为“平均分”(总表须有该列且有数据),则是各班总体成绩对比;如班级选择同一班,科目选择该班不同科目,则是该班各科成绩对比等。 各分数段人数统计一栏内各分数段可自行设置,可按各科目设置分数段(B列选择科目)、按总分设置分数段(B列选择“总分”),按年级名次设置名次段(B列选择年级名次,总表须有该列并有数据)可显示各名次段在各班的人数统计等。 该表可根据需要适当修改,如有多余行可删除,如行不够可往下复制,同样不必要的列也可删除,如各分数段统计列不够也可添加复制。
简易成绩分析系统使用说明 四川省泸州市纳溪区大渡中学 石明富制作 电话:13551664747 email:ddzx2122@sina.com ※※※※一、特色 1、EXCEL平台 本作品采用EXCEL 公式+VBA制作,既可根据你平时使用EXCEL的习惯和方式操作充分发挥EXCEL的功能,又能利用本作品提高效率。 2、结构紧凑,界面简洁 本作品仅有三四个工作表,分别是总表、表册、设置。你可以先在总表输入、导入、复制粘贴或在记录单逐条录入原始成绩,经设置表简单设置后即可在“表册”中根据你的需要自动生成各种表册,包括分班成绩册等各种表册、成绩单、各种统计表等。 ※※※※二、与众不同 本人曾上网搜索到EXCEL平台成绩管理系统不下20款,发现绝大多数都或多或少存在以下问题:总表(或成绩录入表)各项目名称、位置、格式均固定,如班级只能在某列输入且各班级名称必须采用统一格式(如“七(1)”、“七(2)”等)、各科目名称、顺序、录入范围固定等;如果采用公式制作的话,有些单元格还不能移除、拖动、删除等,否则公式会发生错误,当然一不小心公式被你删除或破坏那就更糟了。但本作品为你解决了这几个问题,与众不同: 1、限制条件少,通用性强 只需把原始成绩输入、导入、复制粘贴或在记录单逐条录入总表即可,对总表要求极为宽松:不必整理试卷、非顺序录入;各列(包括科目)名称、位置任意;不受班级、每班人数、科目等数量限制,行列不受限制。简言之,只要您原始成绩表是什么样,把它搞过来就行,只需注意本总表第一行为表格项目且有班级一列和不合并单元格即可,其它不受任何限制。 2、具有容错能力 也许您对函数和公式比较熟悉,知道当公式引用的单元格被移动或删除时公式往往会出错。本作品避免了这个问题。本作品成绩册、统计表和成绩单采用公式生成,数据均来源于总表。可是对总表您尽可放心大胆编辑、修改,对数据进行各种处理,比如可以进行排序、筛选、删除等操作,哪怕移动和删除任何一行、一列,删除任何一个单元格也无妨。 3、具有恢复能力 本作品对成绩册和成绩单,虽然采用函数和公式实现,但您仍可自由编辑排版以便输出,如编辑、修改、删除公式,删除行列,哪怕删除或者清空整张表也可,如果你进行了以上或者其他误操作,您只需重新点击相应按钮即可。 ※※※※三、主要功能 1、查询:查询条件多样,可按姓名查询、按班级查询(分班);按某学科(含总分)某分数段查询;按班内名次(年级名次)段查询(如某班前XX名、年级前XX-XX名)等,各种查询条件还可自由组合。对查询结果,可按某关键字排序后显示,如按班级排名升序可组合出某班全部或班前XX名、年级前XX名排名等,按年级排名升序可组合出年级前XX名排名或全部排名等。 2、统计:根据班级和科目(含总体)按统计范围自动实时生成各项指标(参考人数、平均分、及格人数、及格率、优生人数、优生率、差生人数、差生率等)、各分数段人数统计、年级前XX名在各班分布等。 3、成绩册和成绩条:实时自动按班生成成绩册和成绩条。 ※※※※三、操作指南 在总表中输入、导入、复制粘贴或在记录单逐条录入原始成绩,经设置表简单设置后即可在“表册”中根据你的需要自动生成各种表册,包括分班成绩册等各种表册、成绩单、各种统计表等。 其中,分班成绩册和成绩单、统计分别以VBA和公式两种方式制作,这两种方式各有特点,供你选择:公式方式的优点是当条件变化(如所选班级、科目变化)时显示结果随之实时变化,除非公式被破坏或者刚从其它表册转入本功能你才需要重新点击按钮;VBA方式每次改变条件后必须点击相应按钮才能刷新结果,但对结果你可随意进行各种操作。如果你觉得窗体有可能遮住结果,窗体可移动,可关闭,也可随时按CTRL+Q(W)打开,以便在EXCEL中按你熟悉的方式操作。另总表中还提供了按班级排序、填入总分、平均分、计算班级排名、年级排名、分数超限检查等多种自动化功能。 ※※※※四、温馨提示 1、本成绩分析设计历经本校多年实际应用,并多次修改,但仍不能保证完全符合你校实际,如果你在使用中发现本作品尚有不足的地方,请及时告知,以便进一步改进!如果你校有特别需求,本人愿完全免费为你校量身定做,本人目的在于希望能与广大同行一起交流交流。欢迎来电:13551664747. 2、本成绩分析工作表之间,相互引用,相互关联,不得随意更改删除,也不得对工作表重命名,否则将影响本成绩分析的正常使用。 3、操作前请做好数据备份
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值