Browse Source

Merge remote-tracking branch 'origin/master'

river 4 years ago
parent
commit
bdffb74cbe

+ 11 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/MusicPitchDetailDto.java

@@ -17,6 +17,9 @@ public class MusicPitchDetailDto {
     @ApiModelProperty("频率Hz")
     private float frequency;
 
+    @ApiModelProperty("小节数")
+    private int measureIndex;
+
     public MusicPitchDetailDto() {
     }
 
@@ -54,4 +57,12 @@ public class MusicPitchDetailDto {
     public void setFrequency(float frequency) {
         this.frequency = frequency;
     }
+
+    public int getMeasureIndex() {
+        return measureIndex;
+    }
+
+    public void setMeasureIndex(int measureIndex) {
+        this.measureIndex = measureIndex;
+    }
 }

+ 86 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/WavHeader.java

@@ -0,0 +1,86 @@
+package com.ym.mec.biz.dal.dto;
+
+/**
+ * WAV文件头工具类
+ *
+ * @author maple
+ * @time 2018/4/10.
+ */
+public class WavHeader {
+
+    /**
+     * 返回WAV文件头的byte数组
+     */
+    public static byte[] getWaveHeader(long totalAudioLength, long frameRate, long frameRateSize) {
+        return wavFileHeader(
+                totalAudioLength - 44,
+                totalAudioLength - 44 + 36,
+                frameRate,
+                1,
+                frameRateSize * frameRate * 1 / 8,
+                (byte) frameRateSize
+        );
+    }
+
+    /**
+     * 获取wav文件头
+     *
+     * @param totalAudioLen  -
+     * @param totalDataLen   -
+     * @param longSampleRate - 采样率
+     * @param channels       - 通道数
+     * @param byteRate       -
+     * @param bitsPerSample  - 16/8 bit
+     * @return
+     */
+    private static byte[] wavFileHeader(long totalAudioLen, long totalDataLen, long longSampleRate,
+                                 int channels, long byteRate, byte bitsPerSample) {
+        byte[] header = new byte[44];
+        header[0] = 'R'; // RIFF/WAVE header
+        header[1] = 'I';
+        header[2] = 'F';
+        header[3] = 'F';
+        header[4] = (byte) (totalDataLen & 0xff);
+        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
+        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
+        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
+        header[8] = 'W';
+        header[9] = 'A';
+        header[10] = 'V';
+        header[11] = 'E';
+        header[12] = 'f'; // 'fmt ' chunk
+        header[13] = 'm';
+        header[14] = 't';
+        header[15] = ' ';
+        header[16] = 16; // 4 bytes: size of 'fmt ' chunk
+        header[17] = 0;
+        header[18] = 0;
+        header[19] = 0;
+        header[20] = 1; // format = 1
+        header[21] = 0;
+        header[22] = (byte) channels;
+        header[23] = 0;
+        header[24] = (byte) (longSampleRate & 0xff);
+        header[25] = (byte) ((longSampleRate >> 8) & 0xff);
+        header[26] = (byte) ((longSampleRate >> 16) & 0xff);
+        header[27] = (byte) ((longSampleRate >> 24) & 0xff);
+        header[28] = (byte) (byteRate & 0xff);
+        header[29] = (byte) ((byteRate >> 8) & 0xff);
+        header[30] = (byte) ((byteRate >> 16) & 0xff);
+        header[31] = (byte) ((byteRate >> 24) & 0xff);
+        header[32] = (byte) (channels * (bitsPerSample / 8)); //
+        // block align
+        header[33] = 0;
+        header[34] = bitsPerSample; // bits per sample
+        header[35] = 0;
+        header[36] = 'd';
+        header[37] = 'a';
+        header[38] = 't';
+        header[39] = 'a';
+        header[40] = (byte) (totalAudioLen & 0xff);
+        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
+        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
+        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
+        return header;
+    }
+}

+ 32 - 0
mec-biz/src/main/java/com/ym/mec/biz/dal/dto/WebSocketInfo.java

@@ -0,0 +1,32 @@
+package com.ym.mec.biz.dal.dto;
+
+import com.alibaba.fastjson.JSONObject;
+
+import java.util.HashMap;
+
+/**
+ * @Author Joburgess
+ * @Date 2021/6/17 0017
+ */
+public class WebSocketInfo {
+
+    private HashMap<String, String> header = new HashMap<>();
+
+    private Object body;
+
+    public HashMap<String, String> getHeader() {
+        return header;
+    }
+
+    public void setHeader(HashMap<String, String> header) {
+        this.header = header;
+    }
+
+    public Object getBody() {
+        return body;
+    }
+
+    public void setBody(Object body) {
+        this.body = body;
+    }
+}

+ 14 - 0
mec-biz/src/main/java/com/ym/mec/biz/service/SoundSocketService.java

@@ -0,0 +1,14 @@
+package com.ym.mec.biz.service;
+
+/**
+ * @Author Joburgess
+ * @Date 2021/6/17 0017
+ */
+public interface SoundSocketService {
+
+    String COMMOND = "commond";
+    String MUSIC_XML = "musicXml";
+    String RECORD_START = "recordStart";
+    String RECORD_END = "recordEnd";
+
+}

+ 6 - 0
mec-gateway/mec-gateway-web/pom.xml

@@ -60,6 +60,12 @@
 			<groupId>org.springframework.boot</groupId>
 			<artifactId>spring-boot-starter-security</artifactId>
 		</dependency>
+
+		<dependency>
+			<groupId>com.github.mthizo247</groupId>
+			<artifactId>spring-cloud-netflix-zuul-websocket</artifactId>
+			<version>1.0.0-RELEASE</version>
+		</dependency>
     </dependencies>
 
 	<build>

+ 7 - 1
mec-gateway/mec-gateway-web/src/main/java/com/ym/mec/gateway/web/config/WebSecurityConfig.java

@@ -9,7 +9,13 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
 
 	@Override
 	protected void configure(HttpSecurity http) throws Exception {
-		http.csrf().disable();
+		http.csrf().disable().httpBasic().disable()
+				.authorizeRequests()
+				.antMatchers(
+						"/**"
+				)
+				.permitAll()
+				.anyRequest().authenticated();
 	}
 
 }

+ 23 - 4
mec-teacher/src/main/java/com/ym/mec/teacher/config/WebSocketConfig.java

@@ -1,9 +1,14 @@
 package com.ym.mec.teacher.config;
 
+import com.ym.mec.teacher.handler.WebSocketHandler;
+import com.ym.mec.teacher.interceptor.WebSocketHandshakeInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.web.socket.config.annotation.EnableWebSocket;
-import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
+import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
+import org.springframework.web.socket.server.standard.ServletServerContainerFactoryBean;
 
 /**
  * @Author Joburgess
@@ -11,11 +16,25 @@ import org.springframework.web.socket.server.standard.ServerEndpointExporter;
  */
 @Configuration
 @EnableWebSocket
-public class WebSocketConfig {
+public class WebSocketConfig implements WebSocketConfigurer {
+
+    @Autowired
+    private WebSocketHandler webSocketHandler;
+    @Autowired
+    private WebSocketHandshakeInterceptor webSocketHandshakeInterceptor;
+
+    @Override
+    public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
+        webSocketHandlerRegistry.addHandler(webSocketHandler, "/ws")
+                .addInterceptors(webSocketHandshakeInterceptor);
+    }
 
     @Bean
-    public ServerEndpointExporter serverEndpoint() {
-        return new ServerEndpointExporter();
+    public ServletServerContainerFactoryBean createWebSocketContainer() {
+        ServletServerContainerFactoryBean container = new ServletServerContainerFactoryBean();
+        container.setMaxTextMessageBufferSize(8192*4);
+        container.setMaxBinaryMessageBufferSize(8192*4);
+        return container;
     }
 
 }

+ 36 - 0
mec-teacher/src/main/java/com/ym/mec/teacher/controller/SoundController.java

@@ -1,20 +1,30 @@
 package com.ym.mec.teacher.controller;
 
 import com.alibaba.fastjson.JSON;
+import com.ym.mec.auth.api.client.SysUserFeignService;
+import com.ym.mec.auth.api.entity.SysUser;
 import com.ym.mec.biz.dal.dto.MusicPitchDetailDto;
 import com.ym.mec.biz.service.SoundService;
 import com.ym.mec.common.controller.BaseController;
 import com.ym.mec.common.entity.HttpResponseResult;
+import com.ym.mec.teacher.handler.WebSocketHandler;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.apache.commons.lang3.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.messaging.handler.annotation.MessageMapping;
+import org.springframework.messaging.handler.annotation.SendTo;
+import org.springframework.messaging.simp.SimpMessagingTemplate;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.socket.TextMessage;
 
+import java.io.IOException;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * @Author Joburgess
@@ -25,6 +35,8 @@ import java.util.List;
 @RestController
 public class SoundController extends BaseController {
 
+    private final Logger LOGGER = LoggerFactory.getLogger(SoundController.class);
+
     @Autowired
     private SoundService soundService;
 
@@ -44,4 +56,28 @@ public class SoundController extends BaseController {
         return soundService.measureCompare(musicXmlInfoList, record);
     }
 
+    @RequestMapping("sendToUser")
+    public HttpResponseResult sendToUser(String phone, String message) throws IOException {
+        if(!WebSocketHandler.WS_CLIENTS.containsKey(phone)){
+            return failed("未上线");
+        }
+        if(!WebSocketHandler.WS_CLIENTS.get(phone).isOpen()){
+            return failed("已离线");
+        }
+        WebSocketHandler.WS_CLIENTS.get(phone).sendMessage(new TextMessage(message));
+        return succeed();
+    }
+
+    @RequestMapping("closeWebSocket")
+    public HttpResponseResult closeWebSocket(String phone) throws IOException {
+        if(!WebSocketHandler.WS_CLIENTS.containsKey(phone)){
+            return failed("未上线");
+        }
+        if(!WebSocketHandler.WS_CLIENTS.get(phone).isOpen()){
+            return failed("已离线");
+        }
+        WebSocketHandler.WS_CLIENTS.get(phone).close();
+        return succeed();
+    }
+
 }

+ 332 - 0
mec-teacher/src/main/java/com/ym/mec/teacher/handler/WebSocketHandler.java

@@ -0,0 +1,332 @@
+package com.ym.mec.teacher.handler;
+
+import be.tarsos.dsp.AudioDispatcher;
+import be.tarsos.dsp.io.jvm.AudioDispatcherFactory;
+import be.tarsos.dsp.pitch.PitchProcessor;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.ym.mec.biz.dal.dto.MusicPitchDetailDto;
+import com.ym.mec.biz.dal.dto.WavHeader;
+import com.ym.mec.biz.dal.dto.WebSocketInfo;
+import com.ym.mec.biz.service.SoundSocketService;
+import com.ym.mec.common.constant.CommonConstants;
+import org.apache.commons.io.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.socket.*;
+import org.springframework.web.socket.handler.AbstractWebSocketHandler;
+
+import javax.sound.sampled.AudioFormat;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.stream.Collectors;
+
+/**
+ * @Author Joburgess
+ * @Date 2021/6/9 0009
+ */
+@Service
+public class WebSocketHandler extends AbstractWebSocketHandler {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(WebSocketHandler.class);
+
+    public static final Map<String, WebSocketSession> WS_CLIENTS = new ConcurrentHashMap<>();
+
+    private BigDecimal oneHundred = new BigDecimal(100);
+
+    AudioFormat audioFormat = new AudioFormat(44100, 16, 1, true, false);
+    PitchProcessor.PitchEstimationAlgorithm algo = PitchProcessor.PitchEstimationAlgorithm.FFT_YIN;
+
+    private String tmpDir = FileUtils.getTempDirectoryPath() + "/soundCompare/";
+
+    private Map<String, RandomAccessFile> userRandomAccessFileMap = new ConcurrentHashMap<>();
+    private Map<String, Map<Integer, List<MusicPitchDetailDto>>> userMeasureXmlInfoMap = new ConcurrentHashMap<>();
+    private Map<String, Map<Integer, Integer>> userMeasureEndTimeMap = new ConcurrentHashMap<>();
+    private Map<String, Set<Integer>> userMeasureMap = new ConcurrentHashMap<>();
+    private Map<String, Double> userMeasureStartTimeMap = new ConcurrentHashMap<>();
+    private Map<String, List<MusicPitchDetailDto>> userLastMeasurePithInfoMap = new ConcurrentHashMap<>();
+    private Map<String, Map<String, BigDecimal>> userTotalScoreMap = new ConcurrentHashMap<>();
+    private Map<String, Integer> userMusicIdMap = new ConcurrentHashMap<>();
+
+    public WebSocketHandler() {
+        super();
+        File soundDir = new File(tmpDir);
+        if(!soundDir.exists()){
+            soundDir.mkdir();
+        }
+    }
+
+    @Override
+    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
+        String phone = session.getPrincipal().getName().split(":")[1];
+        LOGGER.info("{}上线", phone);
+        WS_CLIENTS.put(phone, session);
+        super.afterConnectionEstablished(session);
+    }
+
+    @Override
+    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
+        super.handleMessage(session, message);
+    }
+
+    @Override
+    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
+        super.handleTextMessage(session, message);
+        String phone = session.getPrincipal().getName().split(":")[1];
+        LOGGER.info("{}: {}", phone, message.getPayload());
+        WebSocketInfo webSocketInfo = JSON.parseObject(message.getPayload(), WebSocketInfo.class);
+        JSONObject bodyObject = (JSONObject) webSocketInfo.getBody();
+
+        String commond = "";
+        if(webSocketInfo.getHeader().containsKey(SoundSocketService.COMMOND)){
+            commond = webSocketInfo.getHeader().get(SoundSocketService.COMMOND);
+        }
+        switch (commond){
+            case SoundSocketService.MUSIC_XML:
+                List<MusicPitchDetailDto> musicXmlInfos = JSON.parseArray(bodyObject.getString("musicXmlInfos"), MusicPitchDetailDto.class);
+                userMusicIdMap.put(phone, bodyObject.getInteger("id"));
+                userLastMeasurePithInfoMap.put(phone, new ArrayList<>());
+                userTotalScoreMap.put(phone, new HashMap<>());
+                userMeasureXmlInfoMap.put(phone, musicXmlInfos.stream().collect(Collectors.groupingBy(MusicPitchDetailDto::getMeasureIndex)));
+                userMeasureEndTimeMap.put(phone, new HashMap<>());
+                for (Map.Entry<Integer, List<MusicPitchDetailDto>> userMeasureXmlInfoEntry : userMeasureXmlInfoMap.get(phone).entrySet()) {
+                    MusicPitchDetailDto musicPitchDetailDto = userMeasureXmlInfoEntry.getValue().stream().max(Comparator.comparing(MusicPitchDetailDto::getTimeStamp)).get();
+                    userMeasureEndTimeMap.get(phone).put(userMeasureXmlInfoEntry.getKey(), musicPitchDetailDto.getTimeStamp()+musicPitchDetailDto.getDuration());
+                }
+                break;
+            case SoundSocketService.RECORD_START:
+                File file = new File(tmpDir+phone + "_"+ userMusicIdMap.get(phone) +"_"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) +".wav");
+                userRandomAccessFileMap.put(phone, new RandomAccessFile(file, "rw"));
+                userMeasureMap.put(phone, new HashSet<>());
+                userMeasureStartTimeMap.put(phone, (double) 0);
+                break;
+            case SoundSocketService.RECORD_END:
+                if(!CollectionUtils.isEmpty(userMeasureEndTimeMap.get(phone))){
+                    measureCompare(phone, userMeasureEndTimeMap.get(phone).keySet().stream().max(Integer::compareTo).get());
+                }
+                calTotalScore(phone);
+                createHeader(phone);
+                break;
+            default:
+                break;
+        }
+    }
+
+    @Override
+    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) throws Exception {
+        super.handleBinaryMessage(session, message);
+        String phone = session.getPrincipal().getName().split(":")[1];
+        if(userRandomAccessFileMap.containsKey(phone)){
+            userRandomAccessFileMap.get(phone).write(message.getPayload().array());
+        }
+        List<MusicPitchDetailDto> recordInfo = new ArrayList<>();
+        AudioDispatcher dispatcher = AudioDispatcherFactory.fromByteArray(message.getPayload().array(), audioFormat, 256, 128);
+        dispatcher.addAudioProcessor(new PitchProcessor(algo, 44100, 256, (pitchDetectionResult, audioEvent) -> {
+            int timeStamp = (int) (userMeasureStartTimeMap.get(phone) + audioEvent.getTimeStamp()*1000);
+            float pitch = pitchDetectionResult.getPitch();
+            recordInfo.add(new MusicPitchDetailDto(timeStamp, pitch));
+        }));
+        dispatcher.run();
+        double recordTime = userRandomAccessFileMap.get(phone).length()/(audioFormat.getFrameSize()*audioFormat.getFrameRate())*1000;
+        userMeasureStartTimeMap.put(phone, recordTime);
+        userLastMeasurePithInfoMap.get(phone).addAll(recordInfo);
+        for (Map.Entry<Integer, Integer> userMeasureEndTimeMapEntry : userMeasureEndTimeMap.get(phone).entrySet()) {
+            if(recordTime>userMeasureEndTimeMapEntry.getValue()){
+                measureCompare(phone, userMeasureEndTimeMapEntry.getKey());
+                userMeasureEndTimeMap.get(phone).remove(userMeasureEndTimeMapEntry.getKey());
+                break;
+            }
+        }
+
+    }
+
+    @Override
+    protected void handlePongMessage(WebSocketSession session, PongMessage message) throws Exception {
+        super.handlePongMessage(session, message);
+        LOGGER.info("心跳信息:{}", new String(message.getPayload().array(), "utf-8"));
+    }
+
+    @Override
+    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
+        super.handleTransportError(session, exception);
+        exception.printStackTrace();
+        String phone = session.getPrincipal().getName().split(":")[1];
+        LOGGER.info("发生了错误,移除客户端: {}", phone);
+        session.close();
+        WS_CLIENTS.remove(phone);
+        createHeader(phone);
+    }
+
+    @Override
+    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
+        super.afterConnectionClosed(session, status);
+        String phone = session.getPrincipal().getName().split(":")[1];
+        LOGGER.info("{}离线", phone);
+        WS_CLIENTS.remove(phone);
+        createHeader(phone);
+    }
+
+    @Override
+    public boolean supportsPartialMessages() {
+        return super.supportsPartialMessages();
+    }
+
+    private void createHeader(String phone) throws IOException {
+        if(!userRandomAccessFileMap.containsKey(phone)){
+            return;
+        }
+        RandomAccessFile randomAccessFile = userRandomAccessFileMap.get(phone);
+        LOGGER.info("音频时长:{}", randomAccessFile.length()/(audioFormat.getFrameSize()*audioFormat.getFrameRate())*1000);
+        randomAccessFile.seek(0);
+        randomAccessFile.write(WavHeader.getWaveHeader(randomAccessFile.length(), (long) audioFormat.getFrameRate(), audioFormat.getSampleSizeInBits()));
+        randomAccessFile.close();
+        userRandomAccessFileMap.remove(phone);
+    }
+
+    private void measureCompare(String phone, int measureIndex) throws IOException {
+        //总分
+        BigDecimal score = BigDecimal.ZERO;
+        //相似度
+        BigDecimal intonation = BigDecimal.ZERO;
+        //节奏
+        BigDecimal cadence = BigDecimal.ZERO;
+        //完整度
+        BigDecimal integrity = BigDecimal.ZERO;
+
+        try {
+            //最低有效频率
+            float minValidFrequency = 20;
+
+            //有效音频数量
+            float validNum = 0;
+            //音频有效阈值
+            float validDuty = 0.7f;
+
+            //音准匹配数量
+            float intonationNum = 0;
+            //音准匹配误差范围
+            float intonationErrRange = 100;
+            //音准有效阈值
+            float intonationValidDuty = 0.8f;
+
+            //节奏匹配数量
+            float cadenceNum = 0;
+            //节奏匹配误差范围
+            float cadenceErrRange = 100;
+            //节奏有效阈值
+            float cadenceValidDuty = 0.7f;
+
+            int totalCompareNum = userMeasureXmlInfoMap.get(phone).get(measureIndex).size();
+
+            for (MusicPitchDetailDto musicXmlInfo : userMeasureXmlInfoMap.get(phone).get(measureIndex)) {
+                int startTimeStamp = musicXmlInfo.getTimeStamp();
+                int endTimeStamp = musicXmlInfo.getTimeStamp()+musicXmlInfo.getDuration();
+
+                //时间范围内有效音准数量
+                float recordValidIntonationNum = 0;
+                //时间范围内有效节奏数量
+                float cadenceValidNum = 0;
+                //时间范围内有效音频数量
+                float recordValidNum = 0;
+                //时间范围内匹配次数
+                float compareNum = 0;
+                for (MusicPitchDetailDto recordInfo : userLastMeasurePithInfoMap.get(phone)) {
+                    //如果在时间范围之外直接跳过
+                    if(recordInfo.getTimeStamp()<startTimeStamp||recordInfo.getTimeStamp()>endTimeStamp){
+                        continue;
+                    }
+                    compareNum++;
+                    //如果在最低有效频率以下则跳过
+                    if(recordInfo.getFrequency()<minValidFrequency){
+                        continue;
+                    }
+                    recordValidNum++;
+                    //如果频率差值在节奏误差范围内
+                    if(recordInfo.getFrequency()-musicXmlInfo.getFrequency()<=cadenceErrRange){
+                        cadenceValidNum++;
+                    }
+                    //如果频率差值在音准误差范围内
+                    if(recordInfo.getFrequency()-musicXmlInfo.getFrequency()<=intonationErrRange){
+                        recordValidIntonationNum++;
+                    }
+                }
+                //有效音频占比
+                float recordValidDuty = recordValidNum/compareNum;
+                if(recordValidDuty<validDuty){
+                    continue;
+                }
+                validNum++;
+                //有效音高占比
+                float intonationDuty = recordValidIntonationNum/compareNum;
+                //有效节奏占比
+                float cadenceDuty = cadenceValidNum/compareNum;
+                if(intonationDuty>=intonationValidDuty){
+                    intonationNum++;
+                }
+                if(cadenceDuty>=cadenceValidDuty){
+                    cadenceNum++;
+                }
+            }
+
+            intonation = new BigDecimal(intonationNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP);
+            cadence = new BigDecimal(cadenceNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP);
+            integrity = new BigDecimal(validNum).divide(new BigDecimal(totalCompareNum), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(oneHundred).setScale(0, BigDecimal.ROUND_HALF_UP);
+        } catch (ArithmeticException e){
+            LOGGER.info("无musicXml信息");
+        }
+
+        if(userTotalScoreMap.get(phone).containsKey("intonation")){
+            userTotalScoreMap.get(phone).put("intonation", intonation.add(userTotalScoreMap.get(phone).get("intonation")));
+        }else{
+            userTotalScoreMap.get(phone).put("intonation", intonation);
+        }
+
+        if(userTotalScoreMap.get(phone).containsKey("cadence")){
+            userTotalScoreMap.get(phone).put("cadence", cadence.add(userTotalScoreMap.get(phone).get("cadence")));
+        }else{
+            userTotalScoreMap.get(phone).put("cadence", cadence);
+        }
+
+        if(userTotalScoreMap.get(phone).containsKey("integrity")){
+            userTotalScoreMap.get(phone).put("integrity", integrity.add(userTotalScoreMap.get(phone).get("integrity")));
+        }else{
+            userTotalScoreMap.get(phone).put("integrity", integrity);
+        }
+        WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(createPushInfo("measureScore", measureIndex, intonation, cadence, integrity))));
+//                LOGGER.info("推送评分结果:{}", phone);
+    }
+
+    private void calTotalScore(String phone) throws IOException {
+        int totalCompareNum = userMeasureXmlInfoMap.get(phone).keySet().size();
+        BigDecimal intonation = userTotalScoreMap.get(phone).get("intonation").divide(new BigDecimal(totalCompareNum), 0, BigDecimal.ROUND_DOWN);
+        BigDecimal cadence = userTotalScoreMap.get(phone).get("cadence").divide(new BigDecimal(totalCompareNum), 0, BigDecimal.ROUND_DOWN);
+        BigDecimal integrity = userTotalScoreMap.get(phone).get("integrity").divide(new BigDecimal(totalCompareNum), 0, BigDecimal.ROUND_DOWN);
+
+        WS_CLIENTS.get(phone).sendMessage(new TextMessage(JSON.toJSONString(createPushInfo("overall", -1, intonation, cadence, integrity))));
+    }
+
+    private WebSocketInfo createPushInfo(String commond, Integer measureIndex,
+                                         BigDecimal intonation, BigDecimal cadence, BigDecimal integrity){
+        WebSocketInfo webSocketInfo = new WebSocketInfo();
+        HashMap<String, String> header = new HashMap<>();
+        header.put("commond", commond);
+        webSocketInfo.setHeader(header);
+        Map<String, Object> result = new HashMap<>();
+        BigDecimal score = intonation.multiply(new BigDecimal(0.45)).add(cadence.multiply(new BigDecimal(0.45))).add(integrity.multiply(new BigDecimal(0.1))).setScale(0, BigDecimal.ROUND_HALF_UP);
+        result.put("score", score);
+        result.put("intonation", intonation);
+        result.put("cadence", cadence);
+        result.put("integrity", integrity);
+        result.put("measureIndex", measureIndex);
+        webSocketInfo.setBody(result);
+        return webSocketInfo;
+    }
+}

+ 28 - 0
mec-teacher/src/main/java/com/ym/mec/teacher/interceptor/WebSocketHandshakeInterceptor.java

@@ -0,0 +1,28 @@
+package com.ym.mec.teacher.interceptor;
+
+import org.springframework.http.server.ServerHttpRequest;
+import org.springframework.http.server.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.socket.WebSocketHandler;
+import org.springframework.web.socket.server.HandshakeInterceptor;
+
+import java.util.Map;
+
+/**
+ * @Author Joburgess
+ * @Date 2021/6/9 0009
+ */
+@Component
+public class WebSocketHandshakeInterceptor implements HandshakeInterceptor {
+
+    @Override
+    public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Map<String, Object> map) throws Exception {
+        return true;
+    }
+
+    @Override
+    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse, WebSocketHandler webSocketHandler, Exception e) {
+
+    }
+
+}

+ 0 - 50
mec-teacher/src/main/java/com/ym/mec/teacher/websocket/SoundWebSocket.java

@@ -1,50 +0,0 @@
-package com.ym.mec.teacher.websocket;
-
-import org.springframework.stereotype.Component;
-
-import javax.websocket.OnClose;
-import javax.websocket.OnMessage;
-import javax.websocket.OnOpen;
-import javax.websocket.Session;
-import javax.websocket.server.ServerEndpoint;
-import java.io.IOException;
-
-/**
- * @Author Joburgess
- * @Date 2021/6/8 0008
- */
-@ServerEndpoint("/soundPoint")
-@Component
-public class SoundWebSocket {
-
-    /**
-     * 连接成功
-     *
-     * @param session
-     */
-    @OnOpen
-    public void onOpen(Session session) {
-        System.out.println("连接成功");
-    }
-
-    /**
-     * 连接关闭
-     *
-     * @param session
-     */
-    @OnClose
-    public void onClose(Session session) {
-        System.out.println("连接关闭");
-    }
-
-    /**
-     * 接收到消息
-     *
-     * @param text
-     */
-    @OnMessage
-    public String onMsg(String text) throws IOException {
-        return "servet 发送:" + text;
-    }
-
-}