├── .gitignore ├── 5sing.iml ├── README.md ├── build └── 5sing.war ├── pom.xml └── src ├── main ├── java │ └── net │ │ └── zfeng │ │ └── sing │ │ ├── api │ │ ├── controller │ │ │ ├── MusicianController.java │ │ │ ├── SearchController.java │ │ │ └── SongController.java │ │ └── service │ │ │ ├── IMusicianService.java │ │ │ ├── ISearchService.java │ │ │ ├── ISongService.java │ │ │ └── impl │ │ │ ├── MusicianService.java │ │ │ ├── SearchService.java │ │ │ └── SongService.java │ │ ├── exception │ │ └── SingDataException.java │ │ ├── filter │ │ └── OriginFilter.java │ │ ├── model │ │ ├── Musician.java │ │ ├── MusicianList.java │ │ ├── ResModel.java │ │ ├── Song.java │ │ └── SongList.java │ │ ├── parser │ │ ├── IMusicianParser.java │ │ ├── IParser.java │ │ ├── ISearchParser.java │ │ ├── ISongParser.java │ │ ├── config │ │ │ ├── SingCategory.java │ │ │ ├── SingType.java │ │ │ └── SingUrl.java │ │ └── impl │ │ │ ├── MusicianParserImpl.java │ │ │ ├── ParserImpl.java │ │ │ ├── SearchParserImpl.java │ │ │ └── SongParserImpl.java │ │ └── utils │ │ └── Conversion.java ├── resources │ ├── config.properties │ ├── spring-mvc.xml │ ├── spring-mybatis.xml │ └── spring.xml └── webapp │ ├── WEB-INF │ └── web.xml │ └── index.jsp └── test └── net └── zfeng └── sing └── parser └── ParserTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | target 3 | .DS_Store 4 | 5sing.iml -------------------------------------------------------------------------------- /5sing.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | file://$MODULE_DIR$/src/main/resources/spring-mvc.xml 22 | file://$MODULE_DIR$/src/main/resources/spring.xml 23 | file://$MODULE_DIR$/src/main/resources/spring-mybatis.xml 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 5singAPI 2 | 已废弃,请使用原生API https://github.com/i5sing/5sing-mobile-api 3 | 4 | ## Usage 5 | ##### header 6 | ```javascript 7 | content-type: 'application/json' 8 | ``` 9 | 10 | ### [get]/api/songs 11 | 12 | 获取热门歌曲 13 | 14 | #### query 15 | | key | value | | 16 | | -------------------|:---------------------------------------------:|:----:| 17 | | type(歌曲类型) | yc(原创) fc(翻唱) bz(伴奏) | 必须 | 18 | | category(歌曲类别) | tj(推荐) hx(候选) zj(自荐) zx(最新) hot(热门) | 必须 | 19 | | page(页数) | 数字1-50 | 可选 | 20 | 21 | ####response 22 | ```json 23 | { 24 | "code": "200", 25 | "message": "", 26 | "data": { 27 | "page": 2, 28 | "list": [ 29 | { 30 | "id": "3000014", 31 | "name": "【雁引歌】天地神风鉴", 32 | "author": "平纱落雁音乐团队", 33 | "style": "", 34 | "clickNumber": 1471275, 35 | "likeNumber": 179, 36 | "downNumber": 0, 37 | "lrcs": "", 38 | "introduction": "", 39 | "address": "" 40 | } 41 | ] 42 | } 43 | } 44 | ``` 45 | 46 | ### [get]/api/songs/:songId 47 | 48 | 获取歌曲详情 49 | 50 | #### query 51 | | key | value | | 52 | | -------------------|:---------------------------------------------:|:----:| 53 | | type(歌曲类型) | yc(原创) fc(翻唱) bz(伴奏) | 必须 | 54 | | page(页数) | 数字1-50 | 可选 | 55 | 56 | #### response 57 | ```json 58 | { 59 | "code": "200", 60 | "message": "", 61 | "data": { 62 | "id": "3014194", 63 | "name": "烟灰", 64 | "author": "三亩地", 65 | "authorImg": "http://img5.5sing.kgimg.com/force/T1sK__Byxv1RXrhCrK_72_72.jpg", 66 | "style": "三亩地", 67 | "clickNumber": 499182, 68 | "likeNumber": 0, 69 | "downNumber": 0, 70 | "lrcs": "烟灰在夜空中飘散,而我已彻底的凌乱,因为又想起你的脸。 还记得单车后的你,像孩子一样的顽皮,那笑容如此的温暖。 穿过繁华落幕的街,独自一人再吃碗面,那味道已不如从前。 惊醒在每一个夜里,我知道已不属于你,就让这梦随风散去。 曾经每个夜里***疯狂,已经变成破碎不堪的幻象。 那些关于争吵对错的执着,已变成孤独后冰冷的呼吸。 不经意间,哭了,所有思念,已变成烈酒,在每个周末狂欢,醉了,依然心痛,在最后一 杯酒中我醒了。 遗忘在角落的相片,用他来点燃这诺言,这样才会好过点。 在没有你睡的房间,点燃一根事后烟,这感觉撕裂我胸膛。 临界在疯狂的边缘,我用力摔碎这思念,让情绪全部发泄。 沉默的我如同死去,在这寂寞的世界里,让我最后一次再爱你。 那些错与对的全部都抛开,让我们享受进入一瞬间。 让这爱与恨全部到达顶点,在这永恒的绝望里回不来。 在爱的顶点,哭了,所有欲望,混合味道,在冰冷的空气里,散了,就这样别了,在最后 的一次疯狂中。", 71 | "introduction": "烟灭了", 72 | "address": "http://data.5sing.kgimg.com/G051/M09/10/1F/04YBAFafJ7OAfPUNAFPj09Dp9pk347.m4a", 73 | "uploadTime": "" 74 | } 75 | } 76 | ``` 77 | 78 | ### [get]/api/musicians 79 | 80 | 获取热门音乐人 81 | 82 | #### query 83 | | key | value | | 84 | | -------------------|:---------------------------------------------:|:----:| 85 | | page(页数) | 数字1-50 | 可选 | 86 | 87 | #### response 88 | ```json 89 | { 90 | "code": "200", 91 | "message": "", 92 | "data": { 93 | "page": 1, 94 | "list": [ 95 | { 96 | "imgAddress": "http://img9.5sing.kgimg.com/force/T1mkd0BybT1RXrhCrK_75_75.jpg", 97 | "name": "NOVO乐队", 98 | "id": "54228108", 99 | "introduction": "" 100 | } 101 | ] 102 | } 103 | } 104 | ``` 105 | 106 | ### [get]/api/songs/space/:userId 107 | 108 | 获取音乐人歌曲 109 | 110 | #### query 111 | | key | value | | 112 | | -------------------|:---------------------------------------------:|:----:| 113 | | type(歌曲类型) | yc(原创) fc(翻唱) bz(伴奏) | 必须 | 114 | | page(页数) | 数字1-50 | 可选 | 115 | 116 | #### response 117 | ```json 118 | { 119 | "code": "200", 120 | "message": "", 121 | "data": { 122 | "page": 0, 123 | "list": [ 124 | { 125 | "id": "", 126 | "name": "时光约定【暖暖同人歌】", 127 | "author": "", 128 | "authorImg": "", 129 | "style": "", 130 | "clickNumber": 9563022, 131 | "likeNumber": 0, 132 | "downNumber": 0, 133 | "lrcs": "", 134 | "introduction": "", 135 | "address": "", 136 | "uploadTime": "2014-12-20" 137 | } 138 | ] 139 | } 140 | } 141 | ``` 142 | 143 | ### [get]/api/musicians/space/:userId 144 | 145 | 获取音乐人粉丝 146 | 147 | #### query 148 | | key | value | | 149 | | -------------------|:---------------------------------------------:|:----:| 150 | | page(页数) | 数字1-50 | 可选 | 151 | 152 | #### response 153 | ```json 154 | { 155 | "code": "200", 156 | "message": "", 157 | "data": { 158 | "page": 0, 159 | "list": [ 160 | { 161 | "imgAddress": "http://static.5sing.kugou.com/images/nan_48.jpg", 162 | "name": "3WT2AHT508", 163 | "id": "54574939", 164 | "introduction": "TA还没有添加简介" 165 | } 166 | ] 167 | } 168 | } 169 | ``` 170 | 171 | ### [post]/api/search 172 | 173 | 搜索 174 | 175 | #### body 176 | | key | value | | 177 | | -------------------|:---------------------------------------------:|:----:| 178 | | type | yc(原创) fc(翻唱) bz(伴奏) user(会员) | 可选 | 179 | | key | 搜索关键字 | 可选 | 180 | | page(页数) | 数字1-50 | 可选 | 181 | 182 | #### response 183 | ```json 184 | //songs 185 | { 186 | "code": "200", 187 | "message": "", 188 | "data": { 189 | "page": 1, 190 | "list": [ 191 | { 192 | "id": "2493529", 193 | "name": "《14forever》", 194 | "author": "陈美伊", 195 | "authorImg": "", 196 | "style": "", 197 | "clickNumber": 0, 198 | "likeNumber": 0, 199 | "downNumber": 0, 200 | "lrcs": "", 201 | "introduction": "", 202 | "address": "", 203 | "uploadTime": "" 204 | } 205 | ] 206 | } 207 | } 208 | 209 | //users 210 | { 211 | "code": "200", 212 | "message": "", 213 | "data": { 214 | "page": 1, 215 | "list": [ 216 | { 217 | "imgAddress": "", 218 | "name": "可心小屋", 219 | "id": "8888383", 220 | "introduction": "我是一个热爱音乐的女孩,1999年2月出生,2010年7月开始课余进行声乐训练。几年来,我陆续录制了..." 221 | } 222 | ] 223 | } 224 | } 225 | ``` 226 | 227 | ## Demo 228 | 229 | http://139.129.24.142:8080/5sing/ 230 | -------------------------------------------------------------------------------- /build/5sing.war: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/i5sing/5singAPI/6901dabd059890d5a3ad2f9561ac4050e60986b0/build/5sing.war -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | net.zfeng 5 | 5sing 6 | war 7 | 1.0 8 | 5sing Maven Webapp 9 | http://maven.apache.org 10 | 11 | 12 | junit 13 | junit 14 | 3.8.1 15 | test 16 | 17 | 18 | javax 19 | javaee-api 20 | 7.0 21 | 22 | 23 | 24 | org.springframework 25 | spring-context 26 | 4.2.4.RELEASE 27 | 28 | 29 | org.springframework 30 | spring-core 31 | 4.2.4.RELEASE 32 | 33 | 34 | org.springframework 35 | spring-beans 36 | 4.2.4.RELEASE 37 | 38 | 39 | org.springframework 40 | spring-web 41 | 4.2.4.RELEASE 42 | 43 | 44 | org.springframework 45 | spring-webmvc 46 | 4.2.4.RELEASE 47 | 48 | 49 | org.springframework 50 | spring-aop 51 | 4.2.4.RELEASE 52 | 53 | 54 | org.springframework 55 | spring-aspects 56 | 4.2.4.RELEASE 57 | 58 | 59 | 60 | 61 | 62 | org.jsoup 63 | jsoup 64 | 1.8.3 65 | 66 | 67 | 68 | 69 | 70 | com.alibaba 71 | fastjson 72 | 1.2.7 73 | 74 | 75 | 76 | 77 | 78 | com.fasterxml.jackson.core 79 | jackson-core 80 | 2.6.5 81 | 82 | 83 | com.fasterxml.jackson.core 84 | jackson-databind 85 | 2.6.5 86 | 87 | 88 | 89 | 90 | 5sing 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/controller/MusicianController.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.controller; 2 | 3 | import net.zfeng.sing.api.service.IMusicianService; 4 | import net.zfeng.sing.exception.SingDataException; 5 | import net.zfeng.sing.model.Musician; 6 | import net.zfeng.sing.model.MusicianList; 7 | import net.zfeng.sing.model.ResModel; 8 | import org.springframework.web.bind.annotation.*; 9 | 10 | import javax.annotation.Resource; 11 | import javax.servlet.http.HttpServletResponse; 12 | 13 | /** 14 | * Created by zhaofeng on 16/2/8. 15 | */ 16 | @RestController 17 | @RequestMapping("/musicians") 18 | public class MusicianController { 19 | @Resource 20 | private IMusicianService musicianService; 21 | 22 | @RequestMapping(method = RequestMethod.GET) 23 | public ResModel getSongs(@RequestParam(defaultValue = "1")Integer page, HttpServletResponse response) { 24 | String code = "200"; 25 | String message = ""; 26 | MusicianList musicianList = null; 27 | 28 | try { 29 | musicianList = musicianService.getMusicians(page); 30 | } catch (SingDataException e) { 31 | code = "400"; 32 | message = e.getMessage(); 33 | response.setStatus(Integer.parseInt(code)); 34 | } 35 | 36 | return new ResModel(code, message, musicianList); 37 | } 38 | 39 | @RequestMapping(method = RequestMethod.GET, value = "/space/{userId:\\d+}") 40 | public ResModel getFuns( 41 | @PathVariable String userId, 42 | @RequestParam(defaultValue = "1") Integer page, 43 | HttpServletResponse response 44 | ) { 45 | String code = "200"; 46 | String message = ""; 47 | MusicianList musicianList = null; 48 | 49 | try { 50 | musicianList = musicianService.getFuns(userId, page); 51 | } catch (SingDataException e) { 52 | code = "400"; 53 | message = e.getMessage(); 54 | response.setStatus(Integer.parseInt(code)); 55 | } 56 | 57 | return new ResModel(code, message, musicianList); 58 | } 59 | 60 | @RequestMapping(method = RequestMethod.GET, value = "/space/{userId:\\d+}/info") 61 | public ResModel getInfo(@PathVariable String userId, HttpServletResponse response) { 62 | String code = "200"; 63 | String message = ""; 64 | Musician musician = null; 65 | 66 | try { 67 | musician = musicianService.getInfo(userId); 68 | } catch (SingDataException e) { 69 | code = "400"; 70 | message = e.getMessage(); 71 | response.setStatus(Integer.parseInt(code)); 72 | } 73 | 74 | return new ResModel(code, message, musician); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/controller/SearchController.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.controller; 2 | 3 | import net.zfeng.sing.api.service.ISearchService; 4 | import net.zfeng.sing.exception.SingDataException; 5 | import net.zfeng.sing.model.ResModel; 6 | import org.springframework.web.bind.annotation.*; 7 | 8 | import javax.annotation.Resource; 9 | import javax.servlet.http.HttpServletResponse; 10 | 11 | /** 12 | * Created by zhaofeng on 16/2/28. 13 | */ 14 | @RestController 15 | @RequestMapping("/search") 16 | public class SearchController { 17 | @Resource 18 | private ISearchService searchService; 19 | 20 | @RequestMapping(method = RequestMethod.POST) 21 | public ResModel search(@RequestBody(required = true) SearchModel searchModel, HttpServletResponse response) { 22 | String code = "200"; 23 | String message = ""; 24 | Object results = null; 25 | 26 | try { 27 | results = searchService.search(searchModel.getType(), searchModel.getKey(), searchModel.getPage()); 28 | } catch (SingDataException e) { 29 | code = "400"; 30 | message = e.getMessage(); 31 | response.setStatus(Integer.parseInt(code)); 32 | } 33 | 34 | return new ResModel(code, message, results); 35 | } 36 | } 37 | /* 38 | * Search Model 不能作为内部类 否则和RequestBody 共同使用报415/400错误. 39 | */ 40 | class SearchModel { 41 | private String type; 42 | private String key; 43 | private Integer page = 1; 44 | 45 | public String getType() { 46 | return type; 47 | } 48 | 49 | public void setType(String type) { 50 | this.type = type; 51 | } 52 | 53 | public String getKey() { 54 | return key; 55 | } 56 | 57 | public void setKey(String key) { 58 | this.key = key; 59 | } 60 | 61 | public Integer getPage() { 62 | return page; 63 | } 64 | 65 | public void setPage(Integer page) { 66 | this.page = page; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/controller/SongController.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.controller; 2 | 3 | import net.zfeng.sing.api.service.ISongService; 4 | import net.zfeng.sing.exception.SingDataException; 5 | import net.zfeng.sing.model.ResModel; 6 | import net.zfeng.sing.model.Song; 7 | import net.zfeng.sing.model.SongList; 8 | import net.zfeng.sing.utils.Conversion; 9 | import org.springframework.web.bind.annotation.*; 10 | 11 | import javax.annotation.Resource; 12 | import javax.servlet.http.HttpServletRequest; 13 | import javax.servlet.http.HttpServletResponse; 14 | 15 | /** 16 | * Created by zhaofeng on 16/2/5. 17 | */ 18 | @RestController 19 | @RequestMapping("/songs") 20 | public class SongController { 21 | @Resource 22 | private ISongService singService; 23 | 24 | @RequestMapping(method = RequestMethod.GET) 25 | public ResModel getSongs( 26 | @RequestParam(defaultValue = "1") Integer page, 27 | @RequestParam(required = true) String type, 28 | @RequestParam(required = true) String category, 29 | HttpServletResponse response 30 | ) { 31 | String code = "200"; 32 | String message = ""; 33 | SongList songs = null; 34 | 35 | try { 36 | songs = singService.getSongs(Conversion.convertSingType(type), Conversion.convertSingCategory(category), page); 37 | } catch (SingDataException e) { 38 | code = "400"; 39 | message = e.getMessage(); 40 | response.setStatus(Integer.parseInt(code)); 41 | } 42 | 43 | return new ResModel(code, message, songs); 44 | } 45 | 46 | @RequestMapping(method = RequestMethod.GET, value = "/{songId:\\d+}") 47 | public ResModel getSong( 48 | @RequestParam(required = true) String type, 49 | @PathVariable String songId, 50 | @RequestParam(defaultValue = "1") Integer page, 51 | HttpServletResponse response 52 | ) { 53 | String code = "200"; 54 | String message = ""; 55 | Song song = null; 56 | 57 | try { 58 | song = singService.getSong(Conversion.convertSingType(type), songId, page); 59 | } catch (SingDataException e) { 60 | code = "400"; 61 | message = e.getMessage(); 62 | response.setStatus(Integer.parseInt(code)); 63 | } 64 | 65 | return new ResModel(code, message, song); 66 | } 67 | 68 | @RequestMapping(method = RequestMethod.GET, value = "/space/{userId:\\d+}") 69 | public ResModel getPersonalSongs( 70 | @RequestParam(required = true) String type, 71 | @PathVariable String userId, 72 | @RequestParam(defaultValue = "1") Integer page, 73 | HttpServletResponse response 74 | ) { 75 | String code = "200"; 76 | String message = ""; 77 | SongList songs = null; 78 | 79 | try { 80 | songs = singService.getPersonalSongs(userId, Conversion.convertSingType(type), page); 81 | } catch (SingDataException e) { 82 | code = "400"; 83 | message = e.getMessage(); 84 | response.setStatus(Integer.parseInt(code)); 85 | } 86 | 87 | return new ResModel(code, message, songs); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/service/IMusicianService.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.service; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Musician; 5 | import net.zfeng.sing.model.MusicianList; 6 | 7 | /** 8 | * Created by zhaofeng on 16/2/8. 9 | */ 10 | public interface IMusicianService { 11 | 12 | MusicianList getMusicians(int page) throws SingDataException; 13 | 14 | MusicianList getFuns(String userId, int page) throws SingDataException; 15 | 16 | Musician getInfo(String userId) throws SingDataException; 17 | } 18 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/service/ISearchService.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.service; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.SongList; 5 | 6 | /** 7 | * Created by zhaofeng on 16/2/28. 8 | */ 9 | public interface ISearchService { 10 | Object search(String type, String key, int page) throws SingDataException; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/service/ISongService.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.service; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.MusicianList; 5 | import net.zfeng.sing.model.Song; 6 | import net.zfeng.sing.model.SongList; 7 | import net.zfeng.sing.parser.config.SingCategory; 8 | import net.zfeng.sing.parser.config.SingType; 9 | import org.springframework.stereotype.Service; 10 | 11 | /** 12 | * Created by zhaofeng on 16/2/5. 13 | */ 14 | public interface ISongService { 15 | 16 | SongList getSongs(SingType type, SingCategory category, int page) throws SingDataException; 17 | 18 | Song getSong(SingType type, String songId, int page) throws SingDataException; 19 | 20 | SongList getPersonalSongs(String userId, SingType type, int page) throws SingDataException; 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/service/impl/MusicianService.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.service.impl; 2 | 3 | import net.zfeng.sing.api.service.IMusicianService; 4 | import net.zfeng.sing.exception.SingDataException; 5 | import net.zfeng.sing.model.Musician; 6 | import net.zfeng.sing.model.MusicianList; 7 | import net.zfeng.sing.parser.IMusicianParser; 8 | import net.zfeng.sing.parser.impl.MusicianParserImpl; 9 | import org.springframework.stereotype.Service; 10 | 11 | /** 12 | * Created by zhaofeng on 16/2/8. 13 | */ 14 | @Service("musicianService") 15 | public class MusicianService implements IMusicianService { 16 | private IMusicianParser parser; 17 | 18 | public MusicianService() { 19 | parser = new MusicianParserImpl(); 20 | } 21 | 22 | public MusicianList getMusicians(int page) throws SingDataException { 23 | return parser.getMusicians(page); 24 | } 25 | 26 | public MusicianList getFuns(String userId, int page) throws SingDataException { 27 | return parser.getFuns(userId, page); 28 | } 29 | 30 | public Musician getInfo(String userId) throws SingDataException { 31 | return parser.getUserInfo(userId); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/service/impl/SearchService.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.service.impl; 2 | 3 | import net.zfeng.sing.api.service.ISearchService; 4 | import net.zfeng.sing.exception.SingDataException; 5 | import net.zfeng.sing.parser.ISearchParser; 6 | import net.zfeng.sing.parser.impl.SearchParserImpl; 7 | import org.springframework.stereotype.Service; 8 | 9 | /** 10 | * Created by zhaofeng on 16/2/28. 11 | */ 12 | @Service("searchService") 13 | public class SearchService implements ISearchService { 14 | private ISearchParser parser; 15 | 16 | public SearchService() { 17 | parser = new SearchParserImpl(); 18 | } 19 | 20 | public Object search(String type, String key, int page) throws SingDataException { 21 | if (type.equals("user")) { 22 | return parser.searchUsers(key, page); 23 | } 24 | return parser.searchSongs(type, key, page); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/api/service/impl/SongService.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.api.service.impl; 2 | 3 | import net.zfeng.sing.api.service.ISongService; 4 | import net.zfeng.sing.exception.SingDataException; 5 | import net.zfeng.sing.model.Song; 6 | import net.zfeng.sing.model.SongList; 7 | import net.zfeng.sing.parser.ISongParser; 8 | import net.zfeng.sing.parser.config.SingCategory; 9 | import net.zfeng.sing.parser.config.SingType; 10 | import net.zfeng.sing.parser.impl.SongParserImpl; 11 | import org.springframework.stereotype.Service; 12 | 13 | /** 14 | * Created by zhaofeng on 16/2/5. 15 | */ 16 | @Service("songService") 17 | public class SongService implements ISongService { 18 | private ISongParser parser; 19 | 20 | public SongService() { 21 | parser = new SongParserImpl(); 22 | } 23 | 24 | public SongList getSongs(SingType type, SingCategory category, int page) throws SingDataException { 25 | return parser.getSongs(type, category, page); 26 | } 27 | 28 | public Song getSong(SingType type, String songId, int page) throws SingDataException { 29 | return parser.getSong(type, page, songId); 30 | } 31 | 32 | public SongList getPersonalSongs(String userId, SingType type, int page) throws SingDataException { 33 | return parser.getPersonalSongs(userId, type, page); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/exception/SingDataException.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.exception; 2 | 3 | /** 4 | * Created by zhaofeng on 16/2/5. 5 | */ 6 | public class SingDataException extends Exception { 7 | 8 | public SingDataException(String msg) { 9 | super(msg); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/filter/OriginFilter.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.filter; 2 | 3 | import javax.servlet.*; 4 | import javax.servlet.http.HttpServletResponse; 5 | import java.io.IOException; 6 | 7 | /** 8 | * Created by zhaofeng on 16/2/28. 9 | */ 10 | public class OriginFilter implements Filter { 11 | public void init(FilterConfig filterConfig) throws ServletException { 12 | 13 | } 14 | 15 | public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { 16 | HttpServletResponse response = (HttpServletResponse) servletResponse; 17 | response.setHeader("Access-Control-Allow-Origin", "*"); 18 | response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 19 | 20 | filterChain.doFilter(servletRequest, servletResponse); 21 | } 22 | 23 | public void destroy() { 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/model/Musician.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.model; 2 | 3 | /** 4 | * Created by zhaofeng on 16/2/8. 5 | */ 6 | public class Musician { 7 | private String imgAddress = ""; 8 | private String name = ""; 9 | private String id = ""; 10 | private String introduction = ""; 11 | 12 | public String getIntroduction() { 13 | return introduction; 14 | } 15 | 16 | public void setIntroduction(String introduction) { 17 | this.introduction = introduction; 18 | } 19 | 20 | public String getImgAddress() { 21 | return imgAddress; 22 | } 23 | 24 | public void setImgAddress(String imgAddress) { 25 | this.imgAddress = imgAddress; 26 | } 27 | 28 | public String getName() { 29 | return name; 30 | } 31 | 32 | public void setName(String name) { 33 | this.name = name; 34 | } 35 | 36 | public String getId() { 37 | return id; 38 | } 39 | 40 | public void setId(String id) { 41 | this.id = id; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/model/MusicianList.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by zhaofeng on 16/2/8. 7 | */ 8 | public class MusicianList { 9 | private int page; 10 | private List list; 11 | 12 | public int getPage() { 13 | return page; 14 | } 15 | 16 | public void setPage(int page) { 17 | this.page = page; 18 | } 19 | 20 | public List getList() { 21 | return list; 22 | } 23 | 24 | public void setList(List list) { 25 | this.list = list; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/model/ResModel.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.model; 2 | 3 | /** 4 | * Created by zhaofeng on 16/2/5. 5 | */ 6 | public class ResModel { 7 | private String code = "200"; 8 | private String message; 9 | private Object data; 10 | 11 | public ResModel() { 12 | 13 | } 14 | 15 | public ResModel(Object data) { 16 | this.data = data; 17 | } 18 | 19 | public ResModel(String code, String message, Object data) { 20 | this.code = code; 21 | this.message = message; 22 | this.data = data; 23 | } 24 | 25 | public String getCode() { 26 | return code; 27 | } 28 | 29 | public void setCode(String code) { 30 | this.code = code; 31 | } 32 | 33 | public String getMessage() { 34 | return message; 35 | } 36 | 37 | public void setMessage(String message) { 38 | this.message = message; 39 | } 40 | 41 | public Object getData() { 42 | return data; 43 | } 44 | 45 | public void setData(Object data) { 46 | this.data = data; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/model/Song.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.model; 2 | 3 | /** 4 | * Created by zhaofeng on 16/2/4. 5 | */ 6 | public class Song { 7 | private String id = ""; 8 | private String name = ""; 9 | private String author = ""; 10 | private String authorImg = ""; 11 | private String style = ""; 12 | private int clickNumber; 13 | private int likeNumber; 14 | private int downNumber; 15 | private String lrcs = ""; 16 | private String introduction = ""; 17 | private String address = ""; 18 | private String uploadTime = ""; 19 | 20 | public String getUploadTime() { 21 | return uploadTime; 22 | } 23 | 24 | public void setUploadTime(String uploadTime) { 25 | this.uploadTime = uploadTime; 26 | } 27 | 28 | public String getAuthorImg() { 29 | return authorImg; 30 | } 31 | 32 | public void setAuthorImg(String authorImg) { 33 | this.authorImg = authorImg; 34 | } 35 | 36 | public String getAddress() { 37 | return address; 38 | } 39 | 40 | public void setAddress(String address) { 41 | this.address = address; 42 | } 43 | 44 | public String getId() { 45 | return id; 46 | } 47 | 48 | public void setId(String id) { 49 | this.id = id; 50 | } 51 | 52 | public String getName() { 53 | return name; 54 | } 55 | 56 | public void setName(String name) { 57 | this.name = name; 58 | } 59 | 60 | public String getAuthor() { 61 | return author; 62 | } 63 | 64 | public void setAuthor(String author) { 65 | this.author = author; 66 | } 67 | 68 | public int getClickNumber() { 69 | return clickNumber; 70 | } 71 | 72 | public void setClickNumber(int clickNumber) { 73 | this.clickNumber = clickNumber; 74 | } 75 | 76 | public int getLikeNumber() { 77 | return likeNumber; 78 | } 79 | 80 | public void setLikeNumber(int likeNumber) { 81 | this.likeNumber = likeNumber; 82 | } 83 | 84 | public int getDownNumber() { 85 | return downNumber; 86 | } 87 | 88 | public void setDownNumber(int downNumber) { 89 | this.downNumber = downNumber; 90 | } 91 | 92 | public String getLrcs() { 93 | return lrcs; 94 | } 95 | 96 | public void setLrcs(String lrcs) { 97 | this.lrcs = lrcs; 98 | } 99 | 100 | public String getIntroduction() { 101 | return introduction; 102 | } 103 | 104 | public void setIntroduction(String introduction) { 105 | this.introduction = introduction; 106 | } 107 | 108 | public String getStyle() { 109 | return style; 110 | } 111 | 112 | public void setStyle(String style) { 113 | this.style = style; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/model/SongList.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by zhaofeng on 16/2/5. 7 | */ 8 | public class SongList { 9 | private int page; 10 | private List list; 11 | 12 | public int getPage() { 13 | return page; 14 | } 15 | 16 | public void setPage(int page) { 17 | this.page = page; 18 | } 19 | 20 | public List getList() { 21 | return list; 22 | } 23 | 24 | public void setList(List list) { 25 | this.list = list; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/IMusicianParser.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Musician; 5 | import net.zfeng.sing.model.MusicianList; 6 | 7 | /** 8 | * Created by zhaofeng on 4/22/16. 9 | */ 10 | public interface IMusicianParser extends IParser { 11 | MusicianList getMusicians(int page) throws SingDataException; 12 | 13 | MusicianList getFuns(String userId, int page) throws SingDataException; 14 | 15 | Musician getUserInfo(String userId) throws SingDataException; 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/IParser.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Musician; 5 | import net.zfeng.sing.model.MusicianList; 6 | import net.zfeng.sing.model.Song; 7 | import net.zfeng.sing.model.SongList; 8 | import net.zfeng.sing.parser.config.SingCategory; 9 | import net.zfeng.sing.parser.config.SingType; 10 | 11 | /** 12 | * Created by zhaofeng on 16/2/4. 13 | */ 14 | public interface IParser { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/ISearchParser.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.MusicianList; 5 | import net.zfeng.sing.model.SongList; 6 | 7 | /** 8 | * Created by zhaofeng on 4/22/16. 9 | */ 10 | public interface ISearchParser extends IParser { 11 | 12 | SongList searchSongs(String type, String key, int page) throws SingDataException; 13 | 14 | MusicianList searchUsers(String key, int page) throws SingDataException; 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/ISongParser.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Song; 5 | import net.zfeng.sing.model.SongList; 6 | import net.zfeng.sing.parser.config.SingCategory; 7 | import net.zfeng.sing.parser.config.SingType; 8 | 9 | /** 10 | * Created by zhaofeng on 4/22/16. 11 | */ 12 | public interface ISongParser extends IParser { 13 | SongList getSongs(SingType type, SingCategory category, int page) throws SingDataException; 14 | 15 | Song getSong(SingType type, int page, String songId) throws SingDataException; 16 | 17 | SongList getPersonalSongs(String authorId, SingType type, int page) throws SingDataException; 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/config/SingCategory.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.config; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by zhaofeng on 16/2/5. 8 | */ 9 | public enum SingCategory { 10 | TUIJIAN("tj"), 11 | HOUXUAN("hx"), 12 | ZIJIAN("zj"), 13 | ZUIXIN("zx"), 14 | HOT("hot"); 15 | 16 | private String text; 17 | 18 | SingCategory(String text) { 19 | this.text = text; 20 | } 21 | 22 | public String getText() { 23 | return this.text; 24 | } 25 | 26 | // Implementing a fromString method on an enum type 27 | private static final Map stringToEnum = new HashMap(); 28 | 29 | static { 30 | // Initialize map from constant name to enum constant 31 | for (SingCategory category : values()) { 32 | stringToEnum.put(category.toString(), category); 33 | } 34 | } 35 | 36 | // Returns Blah for string, or null if string is invalid 37 | public static SingCategory fromString(String symbol) { 38 | return stringToEnum.get(symbol); 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return text; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/config/SingType.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.config; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by zhaofeng on 16/2/5. 8 | */ 9 | public enum SingType { 10 | YUANCHUANG("yc"), 11 | FANCHANG("fc"), 12 | BANZOU("bz"); 13 | 14 | private String text; 15 | 16 | SingType(String text) { 17 | this.text = text; 18 | } 19 | 20 | public String getText() { 21 | return this.text; 22 | } 23 | 24 | // Implementing a fromString method on an enum type 25 | private static final Map stringToEnum = new HashMap(); 26 | 27 | static { 28 | // Initialize map from constant name to enum constant 29 | for (SingType type : values()) { 30 | stringToEnum.put(type.toString(), type); 31 | } 32 | } 33 | 34 | // Returns Blah for string, or null if string is invalid 35 | public static SingType fromString(String symbol) { 36 | return stringToEnum.get(symbol); 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return text; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/config/SingUrl.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.config; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * Created by zhaofeng on 16/2/5. 8 | */ 9 | public enum SingUrl { 10 | SONG_LIST("http://5sing.kugou.com/m/list/{type}-{category}-{page}.html"), 11 | SONG_DETAIL("http://5sing.kugou.com/m/detail/{type}-{songId}-{page}.html"), 12 | MUSICIAN_HOT("http://5sing.kugou.com/m/list/musician-hot-{page}.html"), 13 | AUTHOR_SONG_LIST("http://5sing.kugou.com/m/space/mysongs/{authorId}-{type}-{page}.html"), 14 | AUTHOR_FUNS("http://5sing.kugou.com/m/space/fans/{authorId}-{page}.html"), 15 | AUTHOR_INFO("http://5sing.kugou.com/m/space/{authorId}.html"), 16 | SEARCH("http://5sing.kugou.com/m/search.html?type={type}&key={key}&p={page}"); 17 | 18 | private String text; 19 | 20 | SingUrl(String text) { 21 | this.text = text; 22 | } 23 | 24 | public String getText() { 25 | return this.text; 26 | } 27 | 28 | // Implementing a fromString method on an enum type 29 | private static final Map stringToEnum = new HashMap(); 30 | 31 | static { 32 | // Initialize map from constant name to enum constant 33 | for (SingUrl url : values()) { 34 | stringToEnum.put(url.toString(), url); 35 | } 36 | } 37 | 38 | // Returns Blah for string, or null if string is invalid 39 | public static SingUrl fromString(String symbol) { 40 | return stringToEnum.get(symbol); 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return text; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/impl/MusicianParserImpl.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.impl; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Musician; 5 | import net.zfeng.sing.model.MusicianList; 6 | import net.zfeng.sing.parser.IMusicianParser; 7 | import net.zfeng.sing.parser.config.SingUrl; 8 | import org.jsoup.nodes.Document; 9 | import org.jsoup.nodes.Element; 10 | import org.jsoup.select.Elements; 11 | 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | /** 19 | * Created by zhaofeng on 4/22/16. 20 | */ 21 | public class MusicianParserImpl extends ParserImpl implements IMusicianParser{ 22 | /** 23 | * 获取热门歌手列表 24 | * 25 | * @param page 26 | * @return 27 | */ 28 | public MusicianList getMusicians(int page) throws SingDataException { 29 | MusicianList musicianList = new MusicianList(); 30 | List musicians = new ArrayList(); 31 | Pattern userIdPattern = Pattern.compile(UserIdRE); 32 | 33 | try { 34 | Document doc = parserHTML(SingUrl.MUSICIAN_HOT.getText().replace("{page}", page + "")); 35 | Elements imgEls = doc.getElementById("photolist").getElementsByTag("a"); 36 | int i = -1; 37 | while (i++ < imgEls.size() - 1) { 38 | Element imgEl = imgEls.get(i); 39 | Matcher userIdMatcher = userIdPattern.matcher(imgEl.attr("href")); 40 | 41 | Musician musician = new Musician(); 42 | 43 | if (userIdMatcher.find() && userIdMatcher.group().length() > 1) { 44 | musician.setId(userIdMatcher.group(1)); 45 | } 46 | 47 | musician.setName(imgEl.getElementsByTag("span").get(0).text()); 48 | musician.setImgAddress(imgEl.getElementsByTag("img").get(0).attr("src")); 49 | musicians.add(musician); 50 | } 51 | } catch (IOException e) { 52 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 53 | } 54 | 55 | musicianList.setList(musicians); 56 | musicianList.setPage(page); 57 | return musicianList; 58 | } 59 | 60 | /** 61 | * 获取个人粉丝 62 | * 63 | * @param userId 64 | * @param page 65 | * @return 66 | * @throws SingDataException 67 | */ 68 | public MusicianList getFuns(String userId, int page) throws SingDataException { 69 | MusicianList musicianList = new MusicianList(); 70 | List musicians = new ArrayList(); 71 | String url = SingUrl.AUTHOR_FUNS.getText().replace("{authorId}", userId).replace("{page}", page + ""); 72 | Pattern userIdPattern = Pattern.compile(UserIdRE); 73 | 74 | try { 75 | Document doc = parserHTML(url); 76 | Elements funEls = doc.getElementsByClass("m_fans").get(0).getElementsByTag("li"); 77 | int i = -1; 78 | while (i++ < funEls.size() - 1) { 79 | Element funEl = funEls.get(i); 80 | Musician musician = new Musician(); 81 | 82 | String img = funEl.getElementsByTag("img").get(0).attr("src"); 83 | String name = funEl.getElementsByTag("h6").get(0).ownText(); 84 | String introduction = funEl.getElementsByTag("p").get(0).text(); 85 | String hrefVal = funEl.getElementsByTag("a").get(0).attr("href"); 86 | Matcher userIdMatcher = userIdPattern.matcher(hrefVal); 87 | 88 | if (userIdMatcher.find() && userIdMatcher.group().length() > 1) { 89 | musician.setId(userIdMatcher.group(1)); 90 | } 91 | musician.setImgAddress(img); 92 | musician.setName(name); 93 | musician.setIntroduction(introduction); 94 | 95 | musicians.add(musician); 96 | } 97 | 98 | musicianList.setList(musicians); 99 | } catch (IOException e) { 100 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 101 | } 102 | return musicianList; 103 | } 104 | 105 | /** 106 | * 获取用户信息 107 | * 108 | * @param userId 109 | * @return 110 | * @throws SingDataException 111 | */ 112 | public Musician getUserInfo(String userId) throws SingDataException { 113 | Musician musician = new Musician(); 114 | String url = SingUrl.AUTHOR_INFO.getText().replace("{authorId}", userId); 115 | 116 | try { 117 | Document doc = parserHTML(url); 118 | Element element = doc.getElementsByClass("my_5sing").get(0); 119 | Element imgEl = element.getElementsByTag("img").get(0); 120 | Element introductionEl = element.getElementsByTag("ul").get(0).getElementsByTag("li").get(0); 121 | String name = doc.getElementsByTag("title").get(0).text().split("的")[0]; 122 | 123 | musician.setName(name); 124 | musician.setId(userId); 125 | musician.setImgAddress(imgEl.attr("src")); 126 | musician.setIntroduction(introductionEl.text()); 127 | } catch (IOException e) { 128 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 129 | } 130 | return musician; 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/impl/ParserImpl.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.impl; 2 | 3 | import net.zfeng.sing.parser.IParser; 4 | import org.jsoup.Jsoup; 5 | import org.jsoup.nodes.Document; 6 | 7 | import java.io.IOException; 8 | 9 | /** 10 | * Created by zhaofeng on 16/2/4. 11 | */ 12 | public class ParserImpl implements IParser { 13 | protected static String SingIdRE = "^/m/detail/\\w+-([0-9]+)-\\d+.html$"; 14 | protected static String UserIdRE = "^/m/space/([0-9]+).html$"; 15 | 16 | /** 17 | * 加载并解析指定url的html 18 | * 19 | * @param url 20 | * @return 21 | * @throws IOException 22 | */ 23 | protected Document parserHTML(String url) throws IOException { 24 | return Jsoup.connect(url).get(); 25 | } 26 | 27 | /** 28 | * 删除html中的其他字符 29 | * 30 | * @param str 31 | * @return 32 | */ 33 | protected String deleteExtraChar(String str) { 34 | return str.replaceAll(" ", "").replaceAll(",", "").replaceAll("
", "").replaceAll(" ", ""); 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/impl/SearchParserImpl.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.impl; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Musician; 5 | import net.zfeng.sing.model.MusicianList; 6 | import net.zfeng.sing.model.Song; 7 | import net.zfeng.sing.model.SongList; 8 | import net.zfeng.sing.parser.ISearchParser; 9 | import net.zfeng.sing.parser.config.SingUrl; 10 | import org.jsoup.nodes.Document; 11 | import org.jsoup.nodes.Element; 12 | import org.jsoup.select.Elements; 13 | 14 | import java.io.IOException; 15 | import java.io.UnsupportedEncodingException; 16 | import java.net.URLEncoder; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | /** 23 | * Created by zhaofeng on 4/22/16. 24 | */ 25 | public class SearchParserImpl extends ParserImpl implements ISearchParser{ 26 | /** 27 | * 搜索 28 | * 29 | * @param type 30 | * @param key 31 | * @param page 32 | * @return 33 | * @throws SingDataException 34 | */ 35 | public SongList searchSongs(String type, String key, int page) throws SingDataException { 36 | List songs = new ArrayList(); 37 | SongList songList = new SongList(); 38 | String url = ""; 39 | try { 40 | url = SingUrl.SEARCH.getText().replace("{type}", type).replace("{key}", URLEncoder.encode(key, "UTF-8")).replace("{page}", page + ""); 41 | } catch (UnsupportedEncodingException e) { 42 | throw new SingDataException("encode error \n" + e.getMessage()); 43 | } 44 | Pattern pattern = Pattern.compile(SingIdRE); 45 | 46 | try { 47 | Document doc = parserHTML(url); 48 | Element songListEl = doc.getElementsByClass("list_items").get(0); 49 | Elements songEls = songListEl.getElementsByTag("li"); 50 | int i = -1; 51 | 52 | while (i++ < songEls.size() - 1) { 53 | Element songEl = songEls.get(i); 54 | String href = songEl.getElementsByTag("a").get(0).attr("href"); 55 | String name = songEl.getElementsByTag("h4").get(0).ownText(); 56 | String author = songEl.getElementsByTag("strong").get(0).text(); 57 | Matcher matcher = pattern.matcher(href); 58 | 59 | Song song = new Song(); 60 | song.setName(name); 61 | song.setAuthor(author); 62 | 63 | if (matcher.find() && matcher.group().length() > 1) { 64 | song.setId(matcher.group(1)); 65 | } 66 | 67 | songs.add(song); 68 | } 69 | } catch (IOException e) { 70 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 71 | } 72 | 73 | songList.setPage(page); 74 | songList.setList(songs); 75 | return songList; 76 | } 77 | 78 | public MusicianList searchUsers(String key, int page) throws SingDataException { 79 | MusicianList musicianList = new MusicianList(); 80 | List musicians = new ArrayList(); 81 | String url = ""; 82 | try { 83 | url = SingUrl.SEARCH.getText().replace("{type}", "user").replace("{key}", URLEncoder.encode(key, "UTF-8")).replace("{page}", page + ""); 84 | } catch (UnsupportedEncodingException e) { 85 | throw new SingDataException("encode error \n" + e.getMessage()); 86 | } 87 | Pattern userIdPattern = Pattern.compile(UserIdRE); 88 | 89 | try { 90 | Document doc = parserHTML(url); 91 | Element userListEl = doc.getElementsByClass("m_fans").get(0); 92 | Elements userEls = userListEl.getElementsByTag("li"); 93 | int i = -1; 94 | 95 | while (i++ < userEls.size() - 1) { 96 | Element user = userEls.get(i); 97 | String href = user.getElementsByTag("a").get(0).attr("href"); 98 | String name = user.getElementsByTag("h6").get(0).text(); 99 | String introduction = user.getElementsByTag("p").get(0).text(); 100 | Matcher userIdMatcher = userIdPattern.matcher(href); 101 | 102 | Musician musician = new Musician(); 103 | 104 | musician.setName(name); 105 | musician.setIntroduction(introduction); 106 | 107 | if (userIdMatcher.find() && userIdMatcher.group().length() > 1) { 108 | musician.setId(userIdMatcher.group(1)); 109 | } 110 | 111 | musicians.add(musician); 112 | } 113 | } catch (IOException e) { 114 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 115 | } 116 | 117 | musicianList.setPage(page); 118 | musicianList.setList(musicians); 119 | return musicianList; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/parser/impl/SongParserImpl.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser.impl; 2 | 3 | import net.zfeng.sing.exception.SingDataException; 4 | import net.zfeng.sing.model.Song; 5 | import net.zfeng.sing.model.SongList; 6 | import net.zfeng.sing.parser.ISongParser; 7 | import net.zfeng.sing.parser.config.SingCategory; 8 | import net.zfeng.sing.parser.config.SingType; 9 | import net.zfeng.sing.parser.config.SingUrl; 10 | import org.jsoup.nodes.Document; 11 | import org.jsoup.nodes.Element; 12 | import org.jsoup.select.Elements; 13 | 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.regex.Matcher; 18 | import java.util.regex.Pattern; 19 | 20 | /** 21 | * Created by zhaofeng on 4/22/16. 22 | */ 23 | public class SongParserImpl extends ParserImpl implements ISongParser { 24 | /** 25 | * 获取5sing歌曲列表 26 | * 27 | * @param page 28 | * @param type 29 | * @param category 30 | * @return 31 | */ 32 | public SongList getSongs(SingType type, SingCategory category, int page) throws SingDataException { 33 | List songs = new ArrayList(); 34 | SongList songList = new SongList(); 35 | Pattern pattern = Pattern.compile(SingIdRE); 36 | 37 | String url = SingUrl.SONG_LIST.getText() 38 | .replace("{type}", type.getText()) 39 | .replace("{category}", category.getText()) 40 | .replace("{page}", page + ""); 41 | 42 | try { 43 | Document doc = parserHTML(url); 44 | Elements songListEl = doc.getElementById("yc_list_tj").getElementsByTag("li"); 45 | int i = -1; 46 | while (i++ < songListEl.size() - 1) { 47 | Element songEl = songListEl.get(i); 48 | Element nameEl = songEl.getElementsByTag("h4").get(0); 49 | Element authorEl = nameEl.getElementsByTag("strong").size() > 0 ? nameEl.getElementsByTag("strong").get(0) : null; 50 | Elements otherEls = songEl.getElementsByTag("span"); 51 | String hrefVal = songEl.getElementsByTag("a").get(1).attr("href"); 52 | 53 | Matcher matcher = pattern.matcher(hrefVal); 54 | 55 | Song song = new Song(); 56 | 57 | if (authorEl != null) { 58 | song.setAuthor(authorEl.text()); 59 | 60 | //删除歌曲名字中的作者信息 61 | authorEl.remove(); 62 | } 63 | 64 | if (matcher.find() && matcher.group().length() > 1) { 65 | song.setId(matcher.group(1)); 66 | } 67 | 68 | song.setName(nameEl.text()); 69 | 70 | if (otherEls.size() > 1) { 71 | int clickNumber = Integer.parseInt(deleteExtraChar(otherEls.get(0).text()).split(":")[1]); 72 | int likeNumber = Integer.parseInt(deleteExtraChar(otherEls.get(1).text()).split(":")[1]); 73 | song.setClickNumber(clickNumber); 74 | song.setLikeNumber(likeNumber); 75 | } 76 | 77 | songs.add(song); 78 | } 79 | } catch (IOException e) { 80 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 81 | } 82 | songList.setList(songs); 83 | songList.setPage(page); 84 | return songList; 85 | } 86 | 87 | /** 88 | * 获取歌曲详情 89 | * 90 | * @param type 91 | * @param page 92 | * @param songId 93 | * @return 94 | */ 95 | public Song getSong(SingType type, int page, String songId) throws SingDataException { 96 | Song song = new Song(); 97 | 98 | String url = SingUrl.SONG_DETAIL.getText() 99 | .replace("{type}", type.getText()) 100 | .replace("{songId}", songId) 101 | .replace("{page}", page + ""); 102 | 103 | try { 104 | Document doc = parserHTML(url); 105 | System.out.print(doc); 106 | Element headEl = doc.getElementsByClass("cd-wrap").get(0).getElementsByTag("img").get(0); 107 | Elements infoEls = doc.getElementsByClass("info-wrap").get(0).getElementsByTag("p"); 108 | Element mp3El = doc.getElementsByClass("play").get(0); 109 | Element lrcEl = doc.getElementsByClass("lrc-wrap").get(0); 110 | 111 | song.setId(songId); 112 | song.setName(infoEls.get(0).text()); 113 | song.setAddress(mp3El.attr("data-songinfo").split(",")[0]); 114 | song.setLrcs(lrcEl.text()); 115 | 116 | String author = deleteExtraChar(infoEls.get(1).text()); 117 | song.setAuthorImg(headEl.attr("src")); 118 | song.setAuthor(author); 119 | } catch (IOException e) { 120 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 121 | } 122 | 123 | return song; 124 | } 125 | 126 | /** 127 | * 获取个人歌曲列表 128 | * 129 | * @param authorId 130 | * @param type 131 | * @param page 132 | * @return 133 | * @throws SingDataException 134 | */ 135 | public SongList getPersonalSongs(String authorId, SingType type, int page) throws SingDataException { 136 | List songs = new ArrayList(); 137 | SongList songList = new SongList(); 138 | Pattern pattern = Pattern.compile(SingIdRE); 139 | 140 | String url = SingUrl.AUTHOR_SONG_LIST.getText() 141 | .replace("{authorId}", authorId) 142 | .replace("{type}", type.getText()) 143 | .replace("{page}", page + ""); 144 | 145 | try { 146 | Document doc = parserHTML(url); 147 | Elements songsEl = doc.getElementsByClass("list_items").get(0).getElementsByTag("li"); 148 | int i = -1; 149 | while (i++ < songsEl.size() - 1) { 150 | Element songEl = songsEl.get(i); 151 | 152 | if (songEl.getElementsByTag("strong").size() == 0) 153 | throw new SingDataException("该音乐人未进行实名认证, 无法获取数据."); 154 | 155 | Song song = new Song(); 156 | 157 | Element infoEl = songEl.getElementsByTag("strong").get(0); 158 | String hrefVal = songEl.getElementsByTag("a").get(0).attr("href"); 159 | String infos = infoEl.text(); 160 | 161 | String name = songEl.getElementsByTag("h4").get(0).ownText(); 162 | 163 | Matcher matcher = pattern.matcher(hrefVal); 164 | 165 | if (matcher.find() && matcher.group().length() > 1) { 166 | song.setId(matcher.group(1)); 167 | } 168 | 169 | song.setName(name); 170 | song.setClickNumber(Integer.parseInt(infos.split(" ")[0].split(":")[1])); 171 | song.setUploadTime(infos.split(" ")[1].split(":")[1]); 172 | 173 | songs.add(song); 174 | } 175 | songList.setList(songs); 176 | } catch (IOException e) { 177 | throw new SingDataException("从五婶获取数据失败\n" + e.getMessage()); 178 | } 179 | return songList; 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /src/main/java/net/zfeng/sing/utils/Conversion.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.utils; 2 | 3 | import net.zfeng.sing.parser.config.SingCategory; 4 | import net.zfeng.sing.parser.config.SingType; 5 | 6 | /** 7 | * Created by zhaofeng on 16/2/5. 8 | */ 9 | public class Conversion { 10 | public static SingType convertSingType(String type) { 11 | SingType mType = SingType.YUANCHUANG; 12 | 13 | if (type.equals("yc")) { 14 | mType = SingType.YUANCHUANG; 15 | } else if (type.equals("fc")) { 16 | mType = SingType.FANCHANG; 17 | } else if (type.equals("bz")) { 18 | mType = SingType.BANZOU; 19 | } 20 | 21 | return mType; 22 | } 23 | 24 | public static SingCategory convertSingCategory(String category) { 25 | SingCategory mCategory = SingCategory.TUIJIAN; 26 | 27 | if (category.equals("tj")) { 28 | mCategory = SingCategory.TUIJIAN; 29 | } else if (category.equals("hx")) { 30 | mCategory = SingCategory.HOUXUAN; 31 | } else if (category.equals("zj")) { 32 | mCategory = SingCategory.ZIJIAN; 33 | } else if (category.equals("hot")) { 34 | mCategory = SingCategory.HOT; 35 | } 36 | 37 | return mCategory; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/resources/config.properties: -------------------------------------------------------------------------------- 1 | hibernate.dialect=org.hibernate.dialect.OracleDialect 2 | driverClassName=oracle.jdbc.driver.OracleDriver 3 | validationQuery=SELECT 1 FROM DUAL 4 | jdbc_url=jdbc:oracle:thin:@localhost:1521:orcl 5 | jdbc_username=feng 6 | jdbc_password=zhaofeng -------------------------------------------------------------------------------- /src/main/resources/spring-mvc.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/main/resources/spring-mybatis.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /src/main/resources/spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | Archetype Created Web Application 7 | 8 | 9 | contextConfigLocation 10 | classpath:spring.xml,classpath:spring-mybatis.xml 11 | 12 | 13 | 14 | encodingFilter 15 | org.springframework.web.filter.CharacterEncodingFilter 16 | 17 | encoding 18 | UTF-8 19 | 20 | 21 | 22 | encodingFilter 23 | /* 24 | 25 | 26 | 27 | OriginFilter 28 | net.zfeng.sing.filter.OriginFilter 29 | 30 | 31 | 32 | 33 | OriginFilter 34 | 35 | /* 36 | 37 | 38 | 39 | spring listener 40 | org.springframework.web.context.ContextLoaderListener 41 | 42 | 43 | 44 | spring mvc servlet 45 | springmvc 46 | org.springframework.web.servlet.DispatcherServlet 47 | 48 | springmvc config 49 | contextConfigLocation 50 | classpath:spring-mvc.xml 51 | 52 | 1 53 | 54 | 55 | springmvc 56 | /api/* 57 | 58 | 59 | 60 | index.html 61 | index.htm 62 | index.jsp 63 | 64 | 65 | -------------------------------------------------------------------------------- /src/main/webapp/index.jsp: -------------------------------------------------------------------------------- 1 | <%@page pageEncoding="utf-8" %> 2 | 3 | 4 | 5 | 6 | 7 |

中国原创音乐基地5SING第三方API

8 | 9 | 10 | -------------------------------------------------------------------------------- /src/test/net/zfeng/sing/parser/ParserTest.java: -------------------------------------------------------------------------------- 1 | package net.zfeng.sing.parser; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import junit.framework.TestCase; 5 | import net.zfeng.sing.exception.SingDataException; 6 | import net.zfeng.sing.parser.impl.SearchParserImpl; 7 | 8 | /** 9 | * Created by zhaofeng on 16/2/28. 10 | */ 11 | public class ParserTest extends TestCase { 12 | private ISearchParser parser = new SearchParserImpl(); 13 | 14 | public void testSearchSongs() { 15 | try { 16 | Object obj = parser.searchSongs("yc", "可心", 1); 17 | System.out.println(JSON.toJSON(obj)); 18 | } catch (SingDataException e) { 19 | e.printStackTrace(); 20 | } 21 | } 22 | 23 | public void testSearchUsers() { 24 | try { 25 | Object obj = parser.searchUsers("可心", 1); 26 | System.out.println(JSON.toJSON(obj)); 27 | } catch (SingDataException e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | } 32 | --------------------------------------------------------------------------------