package top.baogutang.music.service.impl; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.type.TypeReference; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.web.client.RestTemplate; import top.baogutang.music.dao.entity.MusicRecordEntity; import top.baogutang.music.exceptions.BusinessException; import top.baogutang.music.service.IMusicInfoService; import top.baogutang.music.service.IMusicRecordService; import top.baogutang.music.utils.CacheUtil; import top.baogutang.music.utils.OkHttpUtil; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.InputStream; import java.io.OutputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import static top.baogutang.music.constants.CacheKey.KEY_MUSIC_TAG_TOKEN_PREFIX; /** * * @description: * @author: N1KO * @date: 2025/01/23 : 14:53 */ @Slf4j @Service @RefreshScope public class MusicInfoServiceImpl implements IMusicInfoService { @Resource private IMusicRecordService musicRecordService; @Resource private RestTemplate restTemplate; @Resource private RedisTemplate redisTemplate; @Resource(name = "commonExecutor") private Executor commonExecutor; @Value("${baogutang.music-tag.token}") private String tokenUrl; @Value("${baogutang.music-tag.token.param1:username}") private String tokenParam1; @Value("${baogutang.music-tag.token.value1:admin}") private String tokenValue1; @Value("${baogutang.music-tag.token.param2:password}") private String tokenParam2; @Value("${baogutang.music-tag.token.value2:admin}") private String tokenValue2; @Value(("${baogutang.music-tag.cover}")) private String coverUrl; @Override public void getCover(String title, String artist, String album, HttpServletResponse response) { MusicRecordEntity musicRecord = musicRecordService.queryByNameOrAlbumOrArtist(title, album, artist); if (Objects.nonNull(musicRecord) && StringUtils.isNotBlank(musicRecord.getPic())) { this.downloadPicAndResponse(musicRecord.getPic(), response); return; } // 获取三方token String token = CacheUtil.cacheOrSupply(KEY_MUSIC_TAG_TOKEN_PREFIX, 1L, TimeUnit.DAYS, redisTemplate, this::geneToken, new TypeReference<>() { }); Map headers = new HashMap<>(); headers.put("authorization", "jwt " + token); headers.put("Content-Type", "application/json"); Map params = new HashMap<>(); if (StringUtils.isBlank(title)) { params.put("title", album); } else { params.put("title", title); } params.put("artist", artist); params.put("album", album); InfoRes> res = this.queryInfo(headers, params); if (Objects.isNull(res) || !Boolean.TRUE.equals(res.getResult()) || CollectionUtils.isEmpty(res.getData())) { log.error("<<<<<<<<<>>>>>>>>>"); return; } MusicInfoRes musicInfoRes = res.getData().get(0); this.downloadPicAndResponse(musicInfoRes.getAlbumImg(), response); } private InfoRes> queryInfo(Map headers, Map params) { InfoRes> res = null; try { params.put("resource", "qmusic"); res = OkHttpUtil.post(coverUrl, headers, params, new TypeReference<>() { }); if (Objects.isNull(res) || !Boolean.TRUE.equals(res.getResult()) || CollectionUtils.isEmpty(res.getData())) { params.put("resource", "netease"); res = OkHttpUtil.post(coverUrl, headers, params, new TypeReference<>() { }); } } catch (Exception e) { log.error("query music info error:{}", e.getMessage(), e); return null; } return res; } private String geneToken() { Map params = new HashMap<>(); params.put(tokenParam1, tokenValue1); params.put(tokenParam2, tokenValue2); TokenRes tokenRes = null; try { tokenRes = OkHttpUtil.post(tokenUrl, params, new TypeReference<>() { }); } catch (Exception e) { log.error("<<<<<<<<<<获取token异常:{}>>>>>>>>>>", e.getMessage(), e); throw new BusinessException("获取token异常!"); } if (Objects.nonNull(tokenRes) && Boolean.TRUE.equals(tokenRes.getResult())) { return tokenRes.getToken(); } throw new BusinessException("获取token异常!"); } private void downloadPicAndResponse(String picUrl, HttpServletResponse response) { // 获取响应实体 ResponseEntity responseEntity = restTemplate.exchange( picUrl, HttpMethod.GET, null, org.springframework.core.io.Resource.class ); // 设置Content-Type MediaType contentType = responseEntity.getHeaders().getContentType(); if (contentType != null) { response.setContentType(contentType.toString()); } else { response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); } // 设置Content-Length(如果可用) List contentLength = responseEntity.getHeaders().get(HttpHeaders.CONTENT_LENGTH); if (contentLength != null && !contentLength.isEmpty()) { response.setHeader(HttpHeaders.CONTENT_LENGTH, contentLength.get(0)); } if (Objects.isNull(responseEntity.getBody())) { log.error("<<<<<<<<<>>>>>>>>>", picUrl); return; } try (InputStream inputStream = responseEntity.getBody().getInputStream(); OutputStream outputStream = response.getOutputStream()) { // 数据传输 byte[] buffer = new byte[8192]; int bytesRead; while ((bytesRead = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, bytesRead); } outputStream.flush(); } catch (Exception e) { log.error("getCover error!picUrl:{},message:{}", picUrl, e.getMessage(), e); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } @Data static class TokenRes { private String token; private Boolean result; } @Data static class InfoRes { private Boolean result; private String code; private T data; } @Data static class MusicInfoRes { private String mid; private String extra; private String notice; private String title; private String singer; private String album; @JsonProperty("album_img") private String albumImg; private String artist; } }