Browse Source

视频切片

tchao 2 years ago
parent
commit
11356b0cf0
31 changed files with 67165 additions and 51 deletions
  1. 57 1
      pom.xml
  2. 53 13
      sookaCms.iml
  3. 1 1
      src/main/java/com/sooka/CmsApplication.java
  4. 204 6
      src/main/java/com/sooka/common/upload/UploadComponent.java
  5. 45 0
      src/main/java/com/sooka/common/upload/UploadController.java
  6. 71 0
      src/main/java/com/sooka/common/utils/Debug.java
  7. 271 0
      src/main/java/com/sooka/common/utils/FFmpegUtils.java
  8. 284 0
      src/main/java/com/sooka/common/utils/FtpHelper.java
  9. 83 0
      src/main/java/com/sooka/common/utils/FtpQueue.java
  10. 121 0
      src/main/java/com/sooka/common/utils/JSONResult.java
  11. 55 0
      src/main/java/com/sooka/common/utils/MediaInfo.java
  12. 212 0
      src/main/java/com/sooka/common/utils/StringExtend.java
  13. 50 0
      src/main/java/com/sooka/common/utils/TranscodeConfig.java
  14. 78 0
      src/main/java/com/sooka/common/utils/UrlToMultipartFile.java
  15. 4 1
      src/main/java/com/sooka/component/shiro/ShiroConfiguration.java
  16. 1 1
      src/main/java/com/sooka/module/web/cms/qyzxControl.java
  17. 25 11
      src/main/resources/application.properties
  18. 2 2
      src/main/resources/static/BJUI/js/bjui-upload.js
  19. 3 1
      src/main/resources/static/www/bcrc-mobile/css/bcrc-phone-page.css
  20. 1 1
      src/main/resources/static/www/bcrc/css/bcrc-page.css
  21. 1345 0
      src/main/resources/static/www/bcrc/css/video-js.css
  22. 57694 0
      src/main/resources/static/www/bcrc/js/video.js
  23. 6410 0
      src/main/resources/static/www/bcrc/js/videojs-contrib-hls.min.js
  24. 14 0
      src/main/resources/templates/cms/content_input.html
  25. 2 0
      src/main/resources/templates/www/syrc-mobile/jlzx-gsxq.html
  26. 2 2
      src/main/resources/templates/www/syrc-mobile/jlzx-gwxq.html
  27. 4 4
      src/main/resources/templates/www/syrc-mobile/qyzx-ssrc.html
  28. 3 3
      src/main/resources/templates/www/syrc-mobile/wlzp.html
  29. 3 1
      src/main/resources/templates/www/syrc/jlzx-gsxq.html
  30. 3 3
      src/main/resources/templates/www/syrc/jlzx-gwxq.html
  31. 64 0
      src/main/resources/templates/www/syrc/news.html

+ 57 - 1
pom.xml

@@ -23,7 +23,9 @@
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
-        <shiro.version>1.4.0</shiro.version>
+        <shiro.version>1.7.1</shiro.version>
+        <javacv.version>1.5.4</javacv.version>
+        <ffmpeg.version>4.3.1-1.5.4</ffmpeg.version>
         <pac4j.version>2.0.0</pac4j.version>
         <!-- MyBatis Generator master Java接口和实体类 -->
         <masterTargetJavaProject>${basedir}/src/main/java</masterTargetJavaProject>
@@ -192,6 +194,11 @@
             <version>1.3.2</version>
         </dependency>
         <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+            <version>2.5</version>
+        </dependency>
+        <dependency>
             <groupId>com.google.guava</groupId>
             <artifactId>guava</artifactId>
             <version>19.0</version>
@@ -332,6 +339,55 @@
             <artifactId>gson</artifactId>
             <version>2.8.7</version>
         </dependency>
+
+        <!--      javacv 和 ffmpeg的依赖包      -->
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>javacv</artifactId>
+            <version>${javacv.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.bytedeco</groupId>
+                    <artifactId>*</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>org.bytedeco</groupId>
+            <artifactId>ffmpeg-platform</artifactId>
+            <version>${ffmpeg.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.6.5</version>
+        </dependency>
+
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+        </dependency>
+
+
+
+        <!---->
+
+        <dependency>
+            <groupId>commons-net</groupId>
+            <artifactId>commons-net</artifactId>
+            <version>3.8.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
     </dependencies>
 
     <build>

+ 53 - 13
sookaCms.iml

@@ -106,21 +106,22 @@
     <orderEntry type="library" name="Maven: org.quartz-scheduler:quartz-jobs:2.2.3" level="project" />
     <orderEntry type="library" name="Maven: org.springframework:spring-context-support:4.3.15.RELEASE" level="project" />
     <orderEntry type="library" name="Maven: org.springframework:spring-beans:4.3.15.RELEASE" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-lang:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-cache:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-hash:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-core:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-cipher:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-core:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-ogdl:1.4.0" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-core:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-lang:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-cache:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-hash:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-core:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-crypto-cipher:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-core:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-config-ogdl:1.7.1" level="project" />
     <orderEntry type="library" name="Maven: commons-beanutils:commons-beanutils:1.9.3" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-event:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-spring:1.4.0" level="project" />
-    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-web:1.4.0" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-event:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-spring:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.apache.shiro:shiro-web:1.7.1" level="project" />
+    <orderEntry type="library" name="Maven: org.owasp.encoder:encoder:1.2.2" level="project" />
     <orderEntry type="library" name="Maven: org.apache.shiro:shiro-ehcache:1.3.2" level="project" />
     <orderEntry type="library" name="Maven: commons-fileupload:commons-fileupload:1.3.2" level="project" />
-    <orderEntry type="library" name="Maven: commons-io:commons-io:2.2" level="project" />
+    <orderEntry type="library" name="Maven: commons-io:commons-io:2.5" level="project" />
     <orderEntry type="library" name="Maven: com.google.guava:guava:19.0" level="project" />
     <orderEntry type="library" name="Maven: org.jodd:jodd-http:3.8.1" level="project" />
     <orderEntry type="library" name="Maven: org.jodd:jodd-core:3.8.1" level="project" />
@@ -176,7 +177,6 @@
     <orderEntry type="library" name="Maven: org.mapstruct:mapstruct:1.0.0.Final" level="project" />
     <orderEntry type="library" name="Maven: io.springfox:springfox-swagger-ui:2.6.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.poi:poi:3.10.1" level="project" />
-    <orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
     <orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml:3.10.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.poi:poi-ooxml-schemas:3.10.1" level="project" />
     <orderEntry type="library" name="Maven: org.apache.xmlbeans:xmlbeans:2.6.0" level="project" />
@@ -228,5 +228,45 @@
     <orderEntry type="library" name="Maven: org.springframework.retry:spring-retry:1.2.2.RELEASE" level="project" />
     <orderEntry type="library" name="Maven: org.scala-lang:scala-library:2.11.0" level="project" />
     <orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.7" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacv:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.openjfx:javafx-graphics:11" level="project" />
+    <orderEntry type="library" name="Maven: org.openjfx:javafx-graphics:win:11" level="project" />
+    <orderEntry type="library" name="Maven: org.openjfx:javafx-base:11" level="project" />
+    <orderEntry type="library" name="Maven: org.openjfx:javafx-base:win:11" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg-platform:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp-platform:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:android-arm:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:android-arm64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:android-x86:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:android-x86_64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:ios-arm64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:ios-x86_64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:linux-armhf:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:linux-arm64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:linux-ppc64le:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:linux-x86:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:linux-x86_64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:macosx-x86_64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:windows-x86:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:javacpp:windows-x86_64:1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-arm:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-arm64:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-x86:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:android-x86_64:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-x86:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-x86_64:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-armhf:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-arm64:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:linux-ppc64le:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:macosx-x86_64:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:windows-x86:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: org.bytedeco:ffmpeg:windows-x86_64:4.3.1-1.5.4" level="project" />
+    <orderEntry type="library" name="Maven: cn.hutool:hutool-all:5.6.5" level="project" />
+    <orderEntry type="library" name="Maven: log4j:log4j:1.2.17" level="project" />
+    <orderEntry type="library" name="Maven: commons-codec:commons-codec:1.10" level="project" />
+    <orderEntry type="library" name="Maven: commons-net:commons-net:3.8.0" level="project" />
+    <orderEntry type="library" name="Maven: org.projectlombok:lombok:1.16.20" level="project" />
   </component>
 </module>

+ 1 - 1
src/main/java/com/sooka/CmsApplication.java

@@ -40,7 +40,7 @@ public class CmsApplication {
 	public MultipartConfigElement multipartConfigElement() {
 		MultipartConfigFactory factory = new MultipartConfigFactory();
 		//  单个数据大小
-		factory.setMaxFileSize("512000KB"); // KB,MB
+		factory.setMaxFileSize("5242880KB"); // KB,MB
 		/// 总上传数据大小
 		factory.setMaxRequestSize("10240000KB");
 		return factory.createMultipartConfig();

+ 204 - 6
src/main/java/com/sooka/common/upload/UploadComponent.java

@@ -1,16 +1,13 @@
 package com.sooka.common.upload;
 
 import com.alibaba.fastjson.JSON;
+import com.sooka.common.constant.CmsConst;
+import com.sooka.common.exception.ApiException;
 import com.sooka.common.upload.bean.UploadBean;
-import com.sooka.common.utils.ControllerUtil;
-import com.sooka.common.utils.PathUtil;
-import com.sooka.common.utils.QiniuUtil;
-import com.sooka.common.utils.StrUtil;
+import com.sooka.common.utils.*;
 import com.sooka.module.web.system.service.AttachmentService;
 import com.sooka.module.web.system.vo.UserVo;
 import com.sooka.mybatis.model.TSysAttachment;
-import com.sooka.common.constant.CmsConst;
-import com.sooka.common.exception.ApiException;
 import jodd.datetime.JDateTime;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -23,7 +20,15 @@ import javax.servlet.http.HttpServletRequest;
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.UUID;
 
 import static com.sun.org.apache.xerces.internal.impl.dv.util.Base64.decode;
@@ -120,6 +125,188 @@ public class UploadComponent {
         }
     }
 
+
+    public UploadBean ftpuploadFile(MultipartFile multipartFile, HttpServletRequest request){
+        TSysAttachment attachment = new TSysAttachment();
+        /** 获取用户会话 **/
+        UserVo userVo  = (UserVo)request.getSession().getAttribute(CmsConst.SITE_USER_SESSION_KEY);
+        if(userVo!=null) {
+            attachment.setUserId(userVo.getUserId().toString());
+            attachment.setUsername(userVo.getUsername());
+        }
+        attachment.setUploadDate(new Date());
+        attachment.setUploadIp(ControllerUtil.getRemoteAddress(request));
+        attachment.setFileSize(Float.valueOf(multipartFile.getSize())/1024);
+        attachment.setFileExtname(multipartFile.getContentType());
+        attachment.setFileKey(UUID.randomUUID().toString().replace("-",""));
+        attachment.setOriginalFilename(multipartFile.getOriginalFilename());
+        /*创建uploadBean*/
+        UploadBean result = new UploadBean();
+        String fileType = this.getFileType(attachment.getOriginalFilename());
+        String fileName = this.getFileName(fileType) ;
+        String newName =this.getNewFileName(fileName);
+        FtpHelper helper=null;
+        if (!multipartFile.isEmpty()) {
+            if (!Boolean.parseBoolean(qiniuUpload)) {
+                File file = new File(this.getUploadPath() + newName);
+                /*如果不存在就创建*/
+                if (!file.getParentFile().exists()) {
+                    file.getParentFile().mkdirs();
+                }
+                try {
+                    //this.writeFile(multipartFile.getBytes(), file);
+                    helper = new FtpHelper() {
+                        @Override
+                        public void complete(JSONResult jsonResult) {
+                            if(jsonResult.isOK()){
+                                //success
+                            }else{
+                                jsonResult.getMsg();
+                                jsonResult.getStatus();
+                            }
+                        }
+				};
+                    helper.uploadFile(multipartFile.getInputStream(), fileName);
+                    attachment.setFilePath(newName);
+                    attachment.setFileName(fileName);
+                    result.setFileUrl(request.getScheme() + "://" + ControllerUtil.getDomain() + "/res/" + attachment.getFileKey() + "." + fileType);
+                    attachmentService.save(attachment);
+                } catch (Exception e) {
+                    throw new ApiException(e.getMessage());
+                }
+            }else {
+                String qiniuFileResult = QiniuUtil.upload(accessKey, secretKey, bucketname, multipartFile);
+                if (!StrUtil.isBlank(qiniuFileResult)) {
+                    String fileKey = JSON.parseObject(qiniuFileResult).getString("key");
+                    String fileUrl = domain + "/" + fileKey;
+                    if (StrUtil.getExtensionName(fileName).equals("jpg") || StrUtil.getExtensionName(fileName).equals("JPG") || StrUtil.getExtensionName(fileName).equals("png") || StrUtil.getExtensionName(fileName).equals("PNG") || StrUtil.getExtensionName(fileName).equals("jpeg") || StrUtil.getExtensionName(fileName).equals("JPEG")) {
+                        fileUrl += "?imageslim";
+                    }
+                    result.setFileUrl(fileUrl);
+                }
+            }
+            return result;
+        }else{
+            throw new ApiException("上传文件不能为空!");
+        }
+    }
+
+    public UploadBean qpuploadFile(MultipartFile multipartFile, HttpServletRequest request,Path tempDir,String videoFolder) {
+        TSysAttachment attachment = new TSysAttachment();
+        /** 获取用户会话 **/
+        UserVo userVo  = (UserVo)request.getSession().getAttribute(CmsConst.SITE_USER_SESSION_KEY);
+        if(userVo!=null) {
+            attachment.setUserId(userVo.getUserId().toString());
+            attachment.setUsername(userVo.getUsername());
+        }
+        attachment.setUploadDate(new Date());
+        attachment.setUploadIp(ControllerUtil.getRemoteAddress(request));
+        attachment.setFileSize(Float.valueOf(multipartFile.getSize())/1024);
+        attachment.setFileExtname(multipartFile.getContentType());
+        attachment.setFileKey(UUID.randomUUID().toString().replace("-",""));
+        attachment.setOriginalFilename(multipartFile.getOriginalFilename());
+        /*创建uploadBean*/
+        UploadBean result = new UploadBean();
+        String fileType = this.getFileType(attachment.getOriginalFilename());
+        String fileName = this.getFileName(fileType) ;
+        String newName =this.getNewFilenew(fileName);
+        if (!multipartFile.isEmpty()) {
+            if (!Boolean.parseBoolean(qiniuUpload)) {
+                File file = new File(this.getUploadPath() + newName);
+                /*如果不存在就创建*/
+                if (!file.getParentFile().exists()) {
+                    file.getParentFile().mkdirs();
+                }
+                TranscodeConfig transcodeConfig=new TranscodeConfig();
+                // 原始文件名称,也就是视频的标题
+                String title = multipartFile.getOriginalFilename();
+
+                // io到临时文件
+                Path tempFile = tempDir.resolve(title);
+                try {
+                    //this.writeFile(multipartFile.getBytes(), file);
+                    /*helper = new FtpHelper() {
+                        @Override
+                        public void complete(JSONResult jsonResult) {
+                            if(jsonResult.isOK()){
+                                //success
+                            }else{
+                                jsonResult.getMsg();
+                                jsonResult.getStatus();
+                            }
+                        }
+                    };
+                    helper.uploadFile(multipartFile.getInputStream(), fileName);*/
+                        multipartFile.transferTo(new File(String.valueOf(tempFile)));
+
+                        // 删除后缀
+                        //title = title.substring(0, title.lastIndexOf(".")) + "-" + UUID.randomUUID().toString().replaceAll("-", "");
+                        title = title.substring(0, title.lastIndexOf("."));
+
+                        // 按照日期生成子目录
+                        String today = this.getNewFilenew()+ attachment.getFileKey();
+                        //String today = DateTimeFormatter.ofPattern("yyyyMMdd").format(LocalDate.now());
+
+                        // 尝试创建视频目录
+                        Path targetFolder = Files.createDirectories(Paths.get(videoFolder, today));
+
+                        //LOGGER.info("创建文件夹目录:{}", targetFolder);
+                        Files.createDirectories(targetFolder);
+
+                        // 执行转码操作
+                        //LOGGER.info("开始转码");
+                        FFmpegUtils.transcodeToM3u8(tempFile.toString(), targetFolder.toString(), transcodeConfig,attachment.getFileKey());
+
+
+                        // 封装结果
+                    //Map<String, Object> videoInfo = new HashMap<>();
+                    //videoInfo.put("title", title);
+                    //videoInfo.put("m3u8", String.join("/", "", today, title, attachment.getFileKey() + ".m3u8"));
+                    //videoInfo.put("poster", String.join("/", "", today, title, "poster.jpg"));
+
+
+                    attachment.setFilePath("\\upload\\100001\\"+attachment.getFileKey()+"\\"+attachment.getFileKey()+".m3u8");
+                    attachment.setFileName(fileName);
+                    result.setFileUrl(request.getScheme() + "://" + ControllerUtil.getDomain() + "/upload/100001/" +attachment.getFileKey()+"/"+ attachment.getFileKey() + ".m3u8");
+                    attachmentService.save(attachment);
+                } catch (Exception e) {
+                    throw new ApiException(e.getMessage());
+                }finally {
+                    // 始终删除临时文件
+                    try{
+                        Files.delete(tempFile);
+                    }catch (Exception e){
+                        e.printStackTrace();
+                    }
+                }
+            }else {
+                String qiniuFileResult = QiniuUtil.upload(accessKey, secretKey, bucketname, multipartFile);
+                if (!StrUtil.isBlank(qiniuFileResult)) {
+                    String fileKey = JSON.parseObject(qiniuFileResult).getString("key");
+                    String fileUrl = domain + "/" + fileKey;
+                    if (StrUtil.getExtensionName(fileName).equals("jpg") || StrUtil.getExtensionName(fileName).equals("JPG") || StrUtil.getExtensionName(fileName).equals("png") || StrUtil.getExtensionName(fileName).equals("PNG") || StrUtil.getExtensionName(fileName).equals("jpeg") || StrUtil.getExtensionName(fileName).equals("JPEG")) {
+                        fileUrl += "?imageslim";
+                    }
+                    result.setFileUrl(fileUrl);
+                }
+            }
+            return result;
+        }else{
+            throw new ApiException("上传文件不能为空!");
+        }
+    }
+
+
+
+
+
+
+
+
+
+
+
+
     public String getUploadPath(){
         String os = System.getProperty("os.name");
         String uploadPath = enableVirtualPath.equals("true")
@@ -186,6 +373,17 @@ public class UploadComponent {
                 + File.separator + jt.getMonth() + File.separator + jt.getDay() + File.separator + fileName;
     }
 
+    public  String getNewFile(){
+        JDateTime jt = new JDateTime();
+        return File.separator + "upload" + File.separator + jt.getYear()
+                + File.separator + jt.getMonth() + File.separator + jt.getDay() + File.separator ;
+    }
+    public  String getNewFilenew(){
+        return File.separator + "upload" + File.separator+ "100001" + File.separator;
+    }
+    public  String getNewFilenew(String fileName){
+        return File.separator + "res" + File.separator+ fileName;
+    }
     public  String getFileType(String fileName) {
         String type = fileName.substring(fileName.lastIndexOf(".") + 1);
         return type;

+ 45 - 0
src/main/java/com/sooka/common/upload/UploadController.java

@@ -3,11 +3,15 @@ package com.sooka.common.upload;
 
 import com.sooka.common.upload.bean.UploadBean;
 import com.sooka.common.utils.CmsUtil;
+import com.sooka.common.utils.FFmpegUtils;
 import com.sooka.common.utils.JsonUtil;
+import com.sooka.common.utils.TranscodeConfig;
 import com.sooka.module.web.system.service.AttachmentService;
 import com.sooka.mybatis.model.TSysAttachment;
 import com.sooka.common.exception.CmsException;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.util.FileCopyUtils;
 import org.springframework.web.bind.annotation.*;
@@ -15,7 +19,18 @@ import org.springframework.web.multipart.MultipartFile;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.FileInputStream;
+import java.io.IOException;
 import java.net.URLEncoder;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.springframework.http.HttpStatus;
 
 
 @Controller
@@ -36,6 +51,15 @@ public class UploadController {
         return JsonUtil.toUploadSUCCESS("上传成功!",result.getFileUrl());
     }
 
+    @RequestMapping("/ftpuploads")
+    @ResponseBody
+    public String ftpupload(@RequestParam("file") MultipartFile multipartFile,
+                         HttpServletRequest request){
+        UploadBean result = uploadComponent.ftpuploadFile(multipartFile,request);
+
+        return JsonUtil.toUploadSUCCESS("上传成功!",result.getFileUrl());
+    }
+
 
     @RequestMapping("/uploads/wangEditorUpload")
     @ResponseBody
@@ -87,5 +111,26 @@ public class UploadController {
             throw new RuntimeException(e.getMessage());
         }
     }
+    @Value("${app.video-folder}")
+    private String videoFolder;
+
+    private Path tempDir = Paths.get(System.getProperty("java.io.tmpdir"));
+
+    /**
+     * 上传视频进行切片处理,返回访问路径
+     * @param video
+     * @param transcodeConfig
+     * @return
+     * @throws IOException
+     */
+
+    @RequestMapping("/qpupload")
+    @ResponseBody
+    public String qpupload(@RequestParam("file") MultipartFile multipartFile,
+                            HttpServletRequest request){
+        UploadBean result = uploadComponent.qpuploadFile(multipartFile,request,tempDir,videoFolder);
+
+        return JsonUtil.toUploadSUCCESS("上传成功!",result.getFileUrl());
+    }
 
 }

+ 71 - 0
src/main/java/com/sooka/common/utils/Debug.java

@@ -0,0 +1,71 @@
+package com.sooka.common.utils;
+
+/**
+ *
+ * @author xxj
+ * @version 创建时间:2017年4月26日 上午9:52:27
+ */
+public class Debug {
+    /**
+     * 格式化输出,打印信息到控制台
+     * @param format
+     * @param args
+     *  @author xxj 2017年4月26日
+     */
+    public static void printFormat(String format,Object ...args){
+        if(args==null){
+            System.out.println(format);
+        }
+        System.out.println(java.text.MessageFormat.format(format, args));
+    }
+    /**
+     * 格式化输出,打印信息到控制台
+     *  @author xxj 2017年4月26日
+     */
+    public static void print(Object ...msg){
+        if(msg==null){
+            return;
+        }
+        for(Object x:msg){
+            System.out.print(x);
+//			System.out.print(' ');
+        }
+        System.out.println();
+    }
+    /**
+     * 格式化输出,打印信息到控制台
+     *  @author xxj 2017年4月26日
+     */
+    public static void println(Object ...msg){
+        if(msg==null){
+            return;
+        }
+        for(Object x:msg){
+            System.out.println(x);
+        }
+
+    }
+    /**
+     * 打印当前线程的调用堆栈
+     *
+     *  @author xxj 2017年4月26日
+     */
+    public static void printTrack(){
+        StackTraceElement[] st = Thread.currentThread().getStackTrace();
+        if(st==null){
+            System.out.println("无堆栈...");
+            return;
+        }
+        StringBuffer sbf =new StringBuffer();
+        sbf.append(StringExtend.format("调用堆栈[{0}]:",StringExtend.getString(new java.util.Date())));
+        for(StackTraceElement e:st){
+            sbf.append(StringExtend.format(" {0}.{1}() {2} <- {3}"
+                    ,e.getClassName()
+                    ,e.getMethodName()
+                    ,e.getLineNumber()
+                    ,StringExtend.getEnterMark()));
+        }
+        System.out.println(sbf.toString());
+    }
+}
+

+ 271 - 0
src/main/java/com/sooka/common/utils/FFmpegUtils.java

@@ -0,0 +1,271 @@
+package com.sooka.common.utils;
+
+import com.google.gson.Gson;
+import com.sooka.common.utils.MediaInfo;
+import com.sooka.common.utils.TranscodeConfig;
+import org.apache.commons.codec.binary.Hex;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.StringUtils;
+
+import javax.crypto.KeyGenerator;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class FFmpegUtils {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(FFmpegUtils.class);
+
+    // 跨平台换行符
+    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
+
+    /**
+     * 生成随机16个字节的AESKEY
+     * @return
+     */
+    private static byte[] genAesKey ()  {
+        try {
+            KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
+            keyGenerator.init(128);
+            return keyGenerator.generateKey().getEncoded();
+        } catch (NoSuchAlgorithmException e) {
+            return null;
+        }
+    }
+
+    /**
+     * 在指定的目录下生成key_info, key文件,返回key_info文件
+     * @param folder
+     * @throws IOException
+     */
+    private static Path genKeyInfo(String folder) throws IOException {
+        // AES 密钥
+        byte[] aesKey = genAesKey();
+        // AES 向量
+        String iv = Hex.encodeHexString(genAesKey());
+
+        // key 文件写入
+        Path keyFile = Paths.get(folder, "key");
+        Files.write(keyFile, aesKey, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+
+        // key_info 文件写入
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("key").append(LINE_SEPARATOR);					// m3u8加载key文件网络路径
+        stringBuilder.append(keyFile.toString()).append(LINE_SEPARATOR);	// FFmeg加载key_info文件路径
+        stringBuilder.append(iv);											// ASE 向量
+
+        Path keyInfo = Paths.get(folder, "key_info");
+
+        Files.write(keyInfo, stringBuilder.toString().getBytes(), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+
+        return keyInfo;
+    }
+
+    /**
+     * 指定的目录下生成 master index.m3u8 文件
+     * @param file			master m3u8文件地址
+     * @param indexPath			访问子index.m3u8的路径
+     * @param bandWidth			流码率
+     * @throws IOException
+     */
+    private static void genIndex(String file, String indexPath, String bandWidth) throws IOException {
+        StringBuilder stringBuilder = new StringBuilder();
+        stringBuilder.append("#EXTM3U").append(LINE_SEPARATOR);
+        stringBuilder.append("#EXT-X-STREAM-INF:BANDWIDTH=" + bandWidth).append(LINE_SEPARATOR);  // 码率
+        stringBuilder.append(indexPath);
+        Files.write(Paths.get(file), stringBuilder.toString().getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
+    }
+
+    /**
+     * 转码视频为m3u8
+     * @param source				源视频
+     * @param destFolder			目标文件夹
+     * @param config				配置信息
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public static void transcodeToM3u8(String source, String destFolder, TranscodeConfig config,String key) throws IOException, InterruptedException {
+
+        // 判断源视频是否存在
+        if (!Files.exists(Paths.get(source))) {
+            throw new IllegalArgumentException("文件不存在:" + source);
+        }
+
+        // 创建工作目录
+        Path workDir = Paths.get(destFolder, "ts");
+        Files.createDirectories(workDir);
+
+        // 在工作目录生成KeyInfo文件
+        Path keyInfo = genKeyInfo(workDir.toString());
+
+        // 构建命令
+        List<String> commands = new ArrayList<>();
+        commands.add("ffmpeg");
+        commands.add("-i");
+        commands.add(source);					// 源文件
+        commands.add("-c:v");
+        commands.add("libx264");				// 视频编码为H264
+        commands.add("-c:a");
+        commands.add("copy");					// 音频直接copy
+        commands.add("-hls_key_info_file");
+        commands.add(keyInfo.toString());		// 指定密钥文件路径
+        commands.add("-hls_time");
+        commands.add(config.getTsSeconds());	// ts切片大小
+        commands.add("-hls_playlist_type");
+        commands.add("vod");					// 点播模式
+        commands.add("-hls_segment_filename");
+        commands.add("%06d.ts");				// ts切片文件名称
+
+        if (StringUtils.hasText(config.getCutStart())) {
+            commands.add("-ss")					;commands.add(config.getCutStart());	// 开始时间
+        }
+        if (StringUtils.hasText(config.getCutEnd())) {
+            commands.add("-to")					;commands.add(config.getCutEnd());		// 结束时间
+        }
+        commands.add(key+".m3u8");														// 生成m3u8文件
+
+        // 构建进程
+        Process process = new ProcessBuilder()
+                .command(commands)
+                .directory(workDir.toFile())
+                .start()
+                ;
+
+        // 读取进程标准输出
+        new Thread(() -> {
+            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+                String line = null;
+                while ((line = bufferedReader.readLine()) != null) {
+                    LOGGER.info(line);
+                }
+            } catch (IOException e) {
+            }
+        }).start();
+
+        // 读取进程异常输出
+        new Thread(() -> {
+            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+                String line = null;
+                while ((line = bufferedReader.readLine()) != null) {
+                    LOGGER.info(line);
+                }
+            } catch (IOException e) {
+            }
+        }).start();
+
+
+        // 阻塞直到任务结束
+        if (process.waitFor() != 0) {
+            throw new RuntimeException("视频切片异常");
+        }
+
+        // 切出封面
+        //if (!screenShots(source, String.join(File.separator, destFolder, "poster.jpg"), config.getPoster())) {
+         //   throw new RuntimeException("封面截取异常");
+        //}
+
+        // 获取视频信息
+        final MediaInfo[] mediaInfo = {getMediaInfo(source)};
+        if (mediaInfo[0] == null) {
+            throw new RuntimeException("获取媒体信息异常");
+        }
+
+        // 生成index.m3u8文件
+        //genIndex(String.join(File.separator, destFolder, "index.m3u8"), "ts/index.m3u8", mediaInfo[0].getFormat().getBitRate());
+        genIndex(String.join(File.separator, destFolder, key+".m3u8"), "ts/"+key+".m3u8", mediaInfo[0].getFormat().getBitRate());
+
+        // 删除keyInfo文件
+        Files.delete(keyInfo);
+    }
+
+    /**
+     * 获取视频文件的媒体信息
+     * @param source
+     * @return
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public static MediaInfo getMediaInfo(String source) throws IOException, InterruptedException {
+        List<String> commands = new ArrayList<>();
+        commands.add("ffprobe");
+        commands.add("-i")				;commands.add(source);
+        commands.add("-show_format");
+        commands.add("-show_streams");
+        commands.add("-print_format")	;commands.add("json");
+
+        Process process = new ProcessBuilder(commands)
+                .start();
+
+        MediaInfo mediaInfo = null;
+
+        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+            mediaInfo = new Gson().fromJson(bufferedReader, MediaInfo.class);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        if (process.waitFor() != 0) {
+            return null;
+        }
+
+        return mediaInfo;
+    }
+
+    /**
+     * 截取视频的指定时间帧,生成图片文件
+     * @param source		源文件
+     * @param file			图片文件
+     * @param time			截图时间 HH:mm:ss.[SSS]
+     * @throws IOException
+     * @throws InterruptedException
+     */
+    public static boolean screenShots(String source, String file, String time) throws IOException, InterruptedException {
+
+        List<String> commands = new ArrayList<>();
+        commands.add("ffmpeg");
+        commands.add("-i")				;commands.add(source);
+        commands.add("-ss")				;commands.add(time);
+        commands.add("-y");
+        commands.add("-q:v")			;commands.add("1");
+        commands.add("-frames:v")		;commands.add("1");
+        commands.add("-f");				;commands.add("image2");
+        commands.add(file);
+
+        Process process = new ProcessBuilder(commands)
+                .start();
+
+        // 读取进程标准输出
+        new Thread(() -> {
+            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
+                String line = null;
+                while ((line = bufferedReader.readLine()) != null) {
+                    LOGGER.info(line);
+                }
+            } catch (IOException e) {
+            }
+        }).start();
+
+        // 读取进程异常输出
+        new Thread(() -> {
+            try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
+                String line = null;
+                while ((line = bufferedReader.readLine()) != null) {
+                    LOGGER.error(line);
+                }
+            } catch (IOException e) {
+            }
+        }).start();
+
+        return process.waitFor() == 0;
+    }
+}

+ 284 - 0
src/main/java/com/sooka/common/utils/FtpHelper.java

@@ -0,0 +1,284 @@
+package com.sooka.common.utils;
+
+
+import jodd.datetime.JDateTime;
+import org.apache.commons.net.ftp.FTPClient;
+import org.apache.commons.net.ftp.FTPClientConfig;
+import org.apache.commons.net.ftp.FTPReply;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+@Component
+public abstract class FtpHelper implements Closeable {
+
+    private FTPClient ftpClient = null;
+    boolean _isLogin = false;
+
+    /**
+     * ftp 匿名登录
+     */
+    public JSONResult anonymity(){
+        //如果没有设置ftp用户可将username设为anonymous,密码为任意字符串
+
+        return initFtpClient(loadProperties().get("ftp_hostname"), Integer.parseInt(loadProperties().get("ftp_port")), "anonymous", "");
+    }
+
+    /**
+     * ftp登录
+     */
+    public JSONResult login() {
+        return initFtpClient(loadProperties().get("ftp_hostname"), Integer.parseInt(loadProperties().get("ftp_port")), loadProperties().get("ftp_username"), loadProperties().get("ftp_password"));
+    }
+
+    /**
+     * 初始化ftp服务器
+     */
+    public JSONResult initFtpClient(String hostname,int port, String username, String password) {
+
+        ftpClient = new FTPClient();
+        ftpClient.setControlEncoding("utf-8");
+        try {
+            System.out.println("connecting...ftp服务器:"+hostname+":"+port);
+            //连接ftp服务器
+            ftpClient.connect(hostname, port);
+            //登录ftp服务器
+            ftpClient.login(username, password);
+            //是否成功登录服务器
+            int replyCode = ftpClient.getReplyCode();
+            if(!FTPReply.isPositiveCompletion(replyCode)){
+                return JSONResult.errorMsg("connect failed...ftp服务器:"+hostname+":"+port);
+            }
+            System.out.println("connect successful...ftp服务器:"+hostname+":"+port);
+            return JSONResult.ok();
+        } catch (IOException e) {
+            e.printStackTrace();
+            return JSONResult.errorMsg("初始化ftp失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     *
+     * ftp上传文件 (使用inputstream)
+     * @param ftpDirName ftp 目录名
+     * @param ftpFileName ftp目标文件
+     * @return true||false
+     */
+
+    public void uploadFile(InputStream uploadInputStream
+            , String ftpFileName) {
+
+       /* Debug.printFormat("准备上传 [流] 到 ftp://{0}/{1}"
+                ,loadProperties().get("ftp_DirName")
+                ,ftpFileName);*/
+        Debug.printFormat("准备上传 [流] 到 ftp://{0}/{1}"
+                ,"upload"
+                ,ftpFileName);
+//		if(StringExtend.isNullOrEmpty(ftpDirName))
+//			ftpDirName="/";
+        if(StringExtend.isNullOrEmpty(ftpFileName)){
+            complete(JSONResult.errorMsg("上传文件必须填写文件名!"));
+            return;
+        }
+
+        try {
+
+            if (!login().isOK()){
+                complete(login());
+                return;
+            }
+
+            // 设置上传目录(没有则创建)
+            String newName=this.getNewFileName();
+            /*if (!createDir(loadProperties().get("ftp_DirName")).isOK()){
+                complete(createDir(loadProperties().get("ftp_DirName")));
+                return;
+            }*/
+           if (!createDir(newName).isOK()){
+                complete(createDir(newName));
+                return;
+            }
+
+//            if(createDir(ftpDirName)){
+            ftpClient.setBufferSize(1024);
+            //解决上传中文 txt 文件乱码
+            ftpClient.setControlEncoding("utf-8");
+            FTPClientConfig conf = new FTPClientConfig(FTPClientConfig.SYST_NT);
+            conf.setServerLanguageCode("zh");
+
+            // 设置文件类型(二进制)
+            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
+            // 上传
+            String fileName = new String(ftpFileName.getBytes("utf-8"),"utf-8");
+            if(!ftpClient.storeFile(fileName, uploadInputStream)){
+                complete(JSONResult.errorMsg("文件上传失败:{0}/{1}"));
+                return;
+            }
+
+            uploadInputStream.close();
+            Debug.printFormat("文件上传成功:{0}/{1}"
+                    ,loadProperties().get("ftp_DirName")
+                    ,ftpFileName);
+
+            complete(JSONResult.ok("文件上传成功:{0}/{1}"));
+//            }else {
+//                complete(JSONResult.errorMsg("切入FTP目录失败:"+ftpDirName));
+//            }
+
+        } catch (Exception e) {
+            e.printStackTrace();
+            complete(JSONResult.errorMsg("文件上传失败:{0}/{1}:" + e.getMessage()));
+        } finally {
+            closeFtpConnection();
+            if (uploadInputStream != null) {
+                try {
+                    uploadInputStream.close();
+                }catch (Exception e){
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+    public  String getNewFileName(){
+        JDateTime jt = new JDateTime();
+        return File.separator + "upload" + File.separator + jt.getYear()
+                + File.separator + jt.getMonth() + File.separator + jt.getDay() + File.separator ;
+    }
+    /**
+     * 创建目录(有则切换目录,没有则创建目录)
+     * @param dir
+     * @return
+     */
+    private JSONResult createDir(String dir){
+        if(StringExtend.isNullOrEmpty(dir)){
+            return JSONResult.errorMsg("目录为空,无法创建或切入");
+        }
+        String d;
+        try {
+            //目录编码,解决中文路径问题
+            d = new String(dir.getBytes("utf-8"),"utf-8");
+            //尝试切入目录
+            if(ftpClient.changeWorkingDirectory(d)){
+                return JSONResult.ok("切入目录成功");
+            }
+            dir = StringExtend.trimStart(dir, "/");
+            dir = StringExtend.trimEnd(dir, "/");
+            String[] arr =  dir.split("/");
+            StringBuilder sbfDir=new StringBuilder();
+            //循环生成子目录
+            for(String s : arr){
+                sbfDir.append("/");
+                sbfDir.append(s);
+                //目录编码,解决中文路径问题
+                d = new String(sbfDir.toString().getBytes("utf-8"),"utf-8");
+                //尝试切入目录
+                if(ftpClient.changeWorkingDirectory(d)){
+                    continue;
+                }
+                if(!ftpClient.makeDirectory(d)){
+                    return JSONResult.errorMsg("[失败]ftp创建目录:"+sbfDir.toString());
+                }
+                System.out.println("[成功]创建ftp目录:"+sbfDir.toString());
+            }
+            //将目录切换至指定路径
+            if(!ftpClient.changeWorkingDirectory(d)){
+                return JSONResult.errorMsg("切换目录失败:"+d);
+            }
+            return JSONResult.ok("切换目录成功:"+d);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return JSONResult.errorMsg("[失败]:"+e.getMessage());
+        }
+    }
+
+    /**
+     * 销毁ftp连接
+     */
+    @Override
+    public void close() {
+        closeFtpConnection();
+    }
+
+    /**
+     * 销毁ftp连接
+     */
+    private void closeFtpConnection() {
+        _isLogin = false;
+        if (ftpClient != null) {
+            if (ftpClient.isConnected()) {
+                try {
+                    ftpClient.logout();
+                    ftpClient.disconnect();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+    /**
+     * 加载配置文件
+     * */
+    /*@Value("${ftp_hostname}")
+    private  String ftp_hostname ;
+    @Value("${ftp_port}")
+    private  String ftp_port ;
+    @Value("${ftp_username}")
+    private  String ftp_username ;
+    @Value("${ftp_password}")
+    private  String ftp_password ;
+    @Value("${ftp_DirName}")
+    private  String ftp_DirName ;
+
+    ftp_hostname=127.0.0.1
+ftp_port=21
+ftp_username=bcrc
+ftp_password=bcrc123!
+ftp_DirName=/UploadFiles/
+     */
+
+    public Map<String,String> loadProperties() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd/");
+        Date d = new Date();
+        String dateNowStr = sdf.format(d);
+        Map<String,String> conf=new HashMap<>();
+        Properties prop = new Properties();
+        InputStream in;
+        try {
+			in = this.getClass().getResourceAsStream("/application.properties");
+			prop.load(in);     ///加载属性列表
+			conf.put("ftp_hostname", prop.getProperty("ftp_hostname"));//ftp地址
+			conf.put("ftp_port", prop.getProperty("ftp_port"));//ftp端口
+			conf.put("ftp_username", prop.getProperty("ftp_username"));//ftp用户名
+			conf.put("ftp_password", prop.getProperty("ftp_password"));//ftp密码
+			conf.put("ftp_DirName", prop.getProperty("ftp_DirName")+dateNowStr);//ftp保存路径
+			in.close();
+            //in = this.getClass().getResourceAsStream("/app.properties");
+            //prop.load(in);     ///加载属性列表
+           /* conf.put("ftp_hostname", ftp_hostname);//ftp地址
+            conf.put("ftp_port", ftp_port);//ftp端口
+            conf.put("ftp_username", ftp_username);//ftp用户名
+            conf.put("ftp_password", ftp_password);//ftp密码
+            conf.put("ftp_DirName", ftp_DirName+dateNowStr);//ftp保存路径*/
+            //in.close();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return conf;
+    }
+    /**
+     * 完成后回调
+     * @param jsonResult 参数
+     */
+    public abstract void complete(JSONResult jsonResult);
+
+}
+

+ 83 - 0
src/main/java/com/sooka/common/utils/FtpQueue.java

@@ -0,0 +1,83 @@
+package com.sooka.common.utils;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+
+public class FtpQueue {
+
+    public interface OnComplete {
+        void onComplete(JSONResult jsonResult);
+    }
+
+    private static ArrayList<Data> datas;
+    private static FtpHelper ftpHelper;
+    static {
+        datas = new ArrayList<>();
+    }
+
+    public static void addUpload(InputStream inputStream, String ftpDirName,
+                                 String ftpFileName, OnComplete onComplete){
+
+        datas.add(new Data(inputStream, ftpFileName, onComplete));
+
+        System.err.println("-----FtpQueue count-----"+datas.size());
+
+        upload();
+
+    }
+
+    private static void upload(){
+
+        if (datas.size() == 0){
+            return;
+        }
+
+        if (ftpHelper != null){
+            return;
+        }
+
+        final Data data = datas.remove(0);
+
+        ftpHelper = new FtpHelper() {
+            @Override
+            public void complete(JSONResult jsonResult) {
+                ftpHelper = null;
+                data.onComplete.onComplete(jsonResult);
+                upload();
+            }
+        };
+
+        ftpHelper.uploadFile(data.inputStream, data.ftpFileName);
+
+    }
+
+    private static class Data{
+
+    	InputStream inputStream;
+        String ftpFileName;
+        OnComplete onComplete;
+
+        Data(InputStream inputStream,
+             String ftpFileName, OnComplete onComplete){
+
+            this.inputStream = inputStream;
+            this.ftpFileName = ftpFileName;
+            this.onComplete = onComplete;
+
+        }
+
+    }
+
+    public static int getCount() {
+        return datas.size();
+    }
+
+    public static void clean() {
+        if (ftpHelper != null) {
+            ftpHelper.close();
+            datas.clear();
+            ftpHelper = null;
+        }
+    }
+
+}

+ 121 - 0
src/main/java/com/sooka/common/utils/JSONResult.java

@@ -0,0 +1,121 @@
+package com.sooka.common.utils;
+
+/**
+ * @Description: 自定义响应数据结构
+ * 				这个类是提供给门户,ios,安卓,微信商城用的
+ * 				门户接受此类数据后需要使用本类的方法转换成对于的数据类型格式(类,或者list)
+ * 				其他自行处理
+ * 				200:表示成功
+ * 				500:表示错误,错误信息在msg字段中
+ * 				501:bean验证错误,不管多少个错误都以map形式返回
+ * 				502:拦截器拦截到用户token出错
+ * 				555:异常抛出信息
+ */
+public class JSONResult {
+
+    /**
+     * 响应业务状态
+     */
+    private Integer status;
+
+    /**
+     * 响应消息
+     */
+    private String msg;
+
+    /**
+     * 响应中的数据
+     */
+    private Object data;
+
+    /**
+     * 不使用
+     */
+
+    private String ok;
+
+    public static JSONResult build(Integer status, String msg, Object data) {
+        return new JSONResult(status, msg, data);
+    }
+
+    public static JSONResult ok(Object data) {
+        return new JSONResult(data);
+    }
+
+    public static JSONResult ok() {
+        return new JSONResult(null);
+    }
+    
+    public static JSONResult errorMsg(String msg) {
+        return new JSONResult(500, msg, null);
+    }
+    
+    public static JSONResult errorMap(Object data) {
+        return new JSONResult(501, "error", data);
+    }
+    
+    public static JSONResult errorTokenMsg(String msg) {
+        return new JSONResult(502, msg, null);
+    }
+    
+    public static JSONResult errorException(String msg) {
+        return new JSONResult(555, msg, null);
+    }
+
+    public JSONResult() {
+
+    }
+
+//    public static LeeJSONResult build(Integer status, String msg) {
+//        return new LeeJSONResult(status, msg, null);
+//    }
+
+    public JSONResult(Integer status, String msg, Object data) {
+        this.status = status;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public JSONResult(Object data) {
+        this.status = 200;
+        this.msg = "OK";
+        this.data = data;
+    }
+
+    public Boolean isOK() {
+        return this.status == 200;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getMsg() {
+        return msg;
+    }
+
+    public void setMsg(String msg) {
+        this.msg = msg;
+    }
+
+    public Object getData() {
+        return data;
+    }
+
+    public void setData(Object data) {
+        this.data = data;
+    }
+
+	public String getOk() {
+		return ok;
+	}
+
+	public void setOk(String ok) {
+		this.ok = ok;
+	}
+
+}

+ 55 - 0
src/main/java/com/sooka/common/utils/MediaInfo.java

@@ -0,0 +1,55 @@
+package com.sooka.common.utils;
+
+import java.util.List;
+
+import com.google.gson.annotations.SerializedName;
+
+public class MediaInfo {
+    public static class Format {
+        @SerializedName("bit_rate")
+        private String bitRate;
+        public String getBitRate() {
+            return bitRate;
+        }
+        public void setBitRate(String bitRate) {
+            this.bitRate = bitRate;
+        }
+    }
+
+    public static class Stream {
+        @SerializedName("index")
+        private int index;
+
+        @SerializedName("codec_name")
+        private String codecName;
+
+        @SerializedName("codec_long_name")
+        private String codecLongame;
+
+        @SerializedName("profile")
+        private String profile;
+    }
+
+    @SerializedName("streams")
+    private List<Stream> streams;
+
+    @SerializedName("format")
+    private Format format;
+
+    public List<Stream> getStreams() {
+        return streams;
+    }
+
+    public void setStreams(List<Stream> streams) {
+        this.streams = streams;
+    }
+
+    public Format getFormat() {
+        return format;
+    }
+
+    public void setFormat(Format format) {
+        this.format = format;
+    }
+}
+

+ 212 - 0
src/main/java/com/sooka/common/utils/StringExtend.java

@@ -0,0 +1,212 @@
+package com.sooka.common.utils;
+
+import java.math.BigInteger;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.regex.Pattern;
+
+public class StringExtend {
+    /**
+     * 获取换行符,区分不同系统
+     * /r Mac;/n Unix/Linux;/r/n Windows
+     * @return
+     *  @author admin
+     */
+    public static String getEnterMark(){
+        return System.getProperty("line.separator");
+    }
+    /**
+     * 清除首位空格
+     * @return
+     */
+    public static String trim(String msg)
+    {
+        if(msg==null){
+            return null;
+        }
+        return msg.trim();
+    }
+    /**
+     * 字符串内容格式化输出,内部使用{0}\{1}\{2}...为参数占位符</br>
+     * 参数格式:ArgumentIndex[,FormatType[,FormatStyle]] </br>
+     * FormatType 取值:number,date,time,choice </br>
+     * FormatType 样式:如:#.## </br>
+     * 注:'{' 可输出左花括号(单写左花括号会报错,而单写右花括号将正常输出)</br>
+     * @param msg 格式化模板
+     * @param args 不固定参数
+     * @return
+     */
+    public static String format(String msg, Object... args)
+    {
+        return java.text.MessageFormat.format(msg, args);
+    }
+
+    /**
+     * 转换字符串到
+     * @param num
+     * @return
+     *  @author xxj
+     */
+    public static Integer getInt(String num){
+        if(num==null || num.trim().isEmpty()){
+            return 0;
+        }
+
+        if(!num.matches("^(\\d|-)\\d{0,9}$")){
+            return 0;
+        }
+
+        try {
+            return Integer.parseInt(num);
+        } catch (Exception e) {
+            // TODO: handle exception
+            e.printStackTrace();
+            return 0;
+        }
+    }
+    public static String getString(Object obj){
+        return obj == null ? null : obj.toString();
+    }
+    public static String getString(Integer num){
+        return getString(num,"");
+    }
+    public static String getString(Integer num,String def){
+        if(num == null){
+            return def;
+        }
+
+        return num.toString();
+    }
+    public static String getString(Date date){
+        return StringExtend.getString(date);
+    }
+    /**
+     * 字符串是否为空
+     * @param str
+     * @return
+     */
+    public static boolean isNullOrEmpty(String str){
+        return str==null || str.trim().isEmpty();
+    }
+    /**
+     * 比较两个字符串是否相等,忽略大小写
+     * @param str1
+     * @param str2
+     * @return
+     *  @author xxj
+     */
+    public static boolean equalsIgnoreCase(String str1 ,String str2){
+        String tmp = str1==null?"":str1;
+        return tmp.equalsIgnoreCase(str2);
+    }
+    /**
+     * md5 加密
+     * @param str
+     * @return
+     *  @author xxj 2017年4月24日
+     */
+    public static String getMd5(String... str){
+        if(str==null || str.length==0){
+            return "";
+        }
+
+        StringBuffer sbr = new StringBuffer();
+        for(String item : str){
+            sbr.append(item);
+        }
+        // 生成一个MD5加密计算摘要
+        MessageDigest md;
+        try {
+            md = MessageDigest.getInstance("MD5");
+            // 计算md5函数
+            md.update(sbr.toString().getBytes());
+            // digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
+            // BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
+            return new BigInteger(1, md.digest()).toString(16);
+        } catch (NoSuchAlgorithmException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+            return "";
+        }
+    }
+    /**
+     * 删除起始字符
+     * @return
+     *  @author xxj 2017年4月27日
+     */
+    public static String trimStart(String str,String trim){
+        if(str==null){
+            return null;
+        }
+
+        return str.replaceAll("^("+trim+")+", "");
+    }
+    /**
+     * 删除末尾字符
+     * @return
+     *  @author xxj 2017年4月27日
+     */
+    public static String trimEnd(String str,String trim){
+        if(str==null){
+            return null;
+        }
+
+        return str.replaceAll("("+trim+")+$", "");
+    }
+    /**
+     * 以字符开头
+     * @param s
+     * @return
+     *  @author xxj 2017年4月27日
+     */
+    public static boolean startWith(String str,String s){
+        return str.startsWith(s);
+    }
+    /**
+     * 以字符末尾
+     * @param s
+     * @return
+     *  @author xxj 2017年4月27日
+     */
+    public static boolean endWith(String str,String s){
+        return str.endsWith(s);
+    }
+    /**
+     * 获取 boolean 值(1=true;True=true;)
+     * @param str
+     * @return
+     *  @author xxj 2017年5月2日
+     */
+    public static boolean getBoolean(String str){
+        if(isNullOrEmpty(str)){
+            return false;
+        }
+
+
+        Pattern pattern = Pattern.compile("(1)|(true)", Pattern.CASE_INSENSITIVE);
+        if(pattern.matcher(str).matches()){
+            return true;
+        }
+
+
+        return false;
+    }
+
+    /**
+     * 隐藏银行账号后6位
+     * @param str
+     * @return
+     */
+    public static String bankAccount(String str) {
+        if(isNullOrEmpty(str)){
+            return null;
+        }
+
+        if (str.length()>6) {
+            return str.substring(0, str.length()-6)+"xxxxxx";
+        }
+        return str;
+    }
+}
+

+ 50 - 0
src/main/java/com/sooka/common/utils/TranscodeConfig.java

@@ -0,0 +1,50 @@
+package com.sooka.common.utils;
+
+import lombok.Data;
+
+@Data
+public class TranscodeConfig {
+
+    private String poster = "00:00:00.001";				// 截取封面的时间			HH:mm:ss.[SSS]
+    private String tsSeconds = "300";			// ts分片大小,单位是秒
+    private String cutStart;			// 视频裁剪,开始时间		HH:mm:ss.[SSS]
+    private String cutEnd;				// 视频裁剪,结束时间		HH:mm:ss.[SSS]
+    public String getPoster() {
+        return poster;
+    }
+
+    public void setPoster(String poster) {
+        this.poster = poster;
+    }
+
+    public String getTsSeconds() {
+        return tsSeconds;
+    }
+
+    public void setTsSeconds(String tsSeconds) {
+        this.tsSeconds = tsSeconds;
+    }
+
+    public String getCutStart() {
+        return cutStart;
+    }
+
+    public void setCutStart(String cutStart) {
+        this.cutStart = cutStart;
+    }
+
+    public String getCutEnd() {
+        return cutEnd;
+    }
+
+    public void setCutEnd(String cutEnd) {
+        this.cutEnd = cutEnd;
+    }
+
+    @Override
+    public String toString() {
+        return "TranscodeConfig [poster=" + poster + ", tsSeconds=" + tsSeconds + ", cutStart=" + cutStart + ", cutEnd="
+                + cutEnd + "]";
+    }
+}
+

+ 78 - 0
src/main/java/com/sooka/common/utils/UrlToMultipartFile.java

@@ -0,0 +1,78 @@
+package com.sooka.common.utils;
+
+import org.apache.commons.fileupload.FileItem;
+import org.apache.commons.fileupload.FileItemFactory;
+import org.apache.commons.fileupload.disk.DiskFileItemFactory;
+import org.apache.commons.lang.RandomStringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.multipart.commons.CommonsMultipartFile;
+
+import java.io.*;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+public class UrlToMultipartFile {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(UrlToMultipartFile.class);
+
+    /**
+     * inputStream 转 File
+     */
+    public static File inputStreamToFile(InputStream ins, String name) throws Exception{
+        //System.getProperty("java.io.tmpdir")临时目录+File.separator目录中间的间隔符+文件名
+        File file = new File(System.getProperty("java.io.tmpdir") + File.separator + name);
+        OutputStream os = new FileOutputStream(file);
+        int bytesRead;
+        int len = 8192;
+        byte[] buffer = new byte[len];
+        while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
+            os.write(buffer, 0, bytesRead);
+        }
+        os.close();
+        ins.close();
+        return file;
+    }
+
+    /**
+     * file转multipartFile
+     */
+    public static MultipartFile fileToMultipartFile(File file) {
+        FileItemFactory factory = new DiskFileItemFactory(16, null);
+        FileItem item=factory.createItem(file.getName(),"text/plain",true,file.getName());
+        int bytesRead = 0;
+        byte[] buffer = new byte[8192];
+        try {
+            FileInputStream fis = new FileInputStream(file);
+            OutputStream os = item.getOutputStream();
+            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
+                os.write(buffer, 0, bytesRead);
+            }
+            os.close();
+            fis.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return new CommonsMultipartFile(item);
+    }
+
+    //url转MultipartFile
+    public static MultipartFile urlToMultipartFile(String url) throws Exception {
+        File file = null;
+        MultipartFile multipartFile = null;
+        try {
+            HttpURLConnection httpUrl = (HttpURLConnection) new URL(url).openConnection();
+            httpUrl.connect();
+            file = UrlToMultipartFile.inputStreamToFile(httpUrl.getInputStream(),RandomStringUtils.randomAlphanumeric(8)+".mp4");
+            LOGGER.info("---------"+file+"-------------");
+
+            multipartFile = UrlToMultipartFile.fileToMultipartFile(file);
+            httpUrl.disconnect();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return multipartFile;
+    }
+
+}

+ 4 - 1
src/main/java/com/sooka/component/shiro/ShiroConfiguration.java

@@ -163,7 +163,10 @@ public class ShiroConfiguration {
 		chains.put("/system/cms/content/selectList", "anon");
 		chains.put("/system/cms/dbtUser/selectDbxx", "anon");
 		chains.put("/system/cms/topic/allList", "anon");
-		chains.put("/upload/**","auth");
+		chains.put("/upload/2022/**","auth");
+		chains.put("/upload/2023/**","auth");
+		chains.put("/upload/100001/**","anon");
+		chains.put("/resfilelast/**","anon");
 		chains.put("/dbtUser/dbtUserList", "anon");
 		chains.put("/dbtUser/dbtUserListForSeach", "anon");
 		chains.put("/system/reception/**", "anon");

+ 1 - 1
src/main/java/com/sooka/module/web/cms/qyzxControl.java

@@ -526,7 +526,7 @@ public class qyzxControl {
 			view= new ModelAndView("www/syrc-mobile/qyzx-ssrc");
 		}
 		else{
-			view = new ModelAndView("www/syrc/qyzx-ssrc");
+			view = new ModelAndView("www/syrc/`qyzx-ssrc`");
 		}
 		PageInfo<Map<String,Object>> p;
 		p = zwtdlService.pageAll(pageNumber,pageSize,jl);

+ 25 - 11
src/main/resources/application.properties

@@ -2,15 +2,22 @@
 app.name=@project.name@
 server.port = 80
 
-#spring session
-spring.session.store-type=hash_map
+## 存储转码视频的文件夹
+app.video-folder=D:/upload_file_root
+spring.servlet.multipart.max-file-size=-1
+spring.servlet.multipart.max-request-size=-1
+spring.servlet.multipart.location=${java.io.tmpdir}
+spring.servlet.multipart.file-size-threshold=1MB
+spring.web.resources.static-locations[0]=classpath:/static/
+spring.web.resources.static-locations[1]=file:${app.video-folder}
 
 
+#spring session
+spring.session.store-type=hash_map
 
 #spring aop
 spring.aop.auto=true
 spring.aop.proxy-target-class=true
-
 #ehcache
 spring.cache.type=ehcache
 spring.cache.ehcache.config=classpath:ehcache.xml
@@ -20,15 +27,15 @@ spring.devtools.restart.enabled=true
 
 #datasource
 spring.datasource.driver-class-name=com.mysql.jdbc.Driver
-spring.datasource.url=jdbc:mysql://192.168.1.7:3306/bcrc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
-spring.datasource.username=root
-spring.datasource.password=123456
+#spring.datasource.url=jdbc:mysql://192.168.1.7:3306/bcrc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
+#spring.datasource.username=root
+#spring.datasource.password=123456
 #spring.datasource.url=jdbc:mysql://121.37.83.100:53306/bcrc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=true
 #spring.datasource.username=bcrc
 #spring.datasource.password=bcrc123456
-#spring.datasource.url=jdbc:mysql://127.0.0.1:3306/bcrc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
-#spring.datasource.username=root
-#spring.datasource.password=root
+spring.datasource.url=jdbc:mysql://127.0.0.1:3306/bcrc?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false
+spring.datasource.username=root
+spring.datasource.password=root
 
 
 
@@ -91,8 +98,8 @@ system.login.enabled-kickout = true
 #用户登陆最大会话
 system.login.max-session = 1
 system.http.protocol=http
-system.http.host=www.bccj.com.cn
-#system.http.host=127.0.0.1
+#system.http.host=www.bccj.com.cn
+system.http.host=127.0.0.1
 system.site.name=sookaCms
 system.site.prefix=syrc
 system.site.subfix=.html
@@ -110,6 +117,13 @@ windows.file.upload.path=D:/upload_file_root
 #file upload path linux
 linux.file.upload.path=/home/bcrc/data/upload_file_root/cms
 
+#ftpFileUpload
+ftp_hostname=127.0.0.1
+ftp_port=21
+ftp_username=bcrc
+ftp_password=bcrc123!
+ftp_DirName=/upload_file_root/
+
 #七牛云存储
 qiniu.upload.on = false
 qiniu.access.key =

+ 2 - 2
src/main/resources/static/BJUI/js/bjui-upload.js

@@ -34,7 +34,7 @@
         multi               : false,  //是否允许选择多个文件
         formData            : {},     //发送给服务端的参数,格式:{key1:value1,key2:value2}
         fileObjName         : 'file', //在后端接受文件的参数名称,如PHP中的$_FILES['file']
-        fileSizeLimit       : 204800, //允许上传的文件大小,单位KB
+        fileSizeLimit       : 5242880, //允许上传的文件大小,单位KB
         previewImg          : true,   //是否预览上传图片
         previewLoadimg      : null,   //预览图片前的载入图标
         dragDrop            : false,  //是否允许拖动上传
@@ -498,7 +498,7 @@
                     fileTypeExts  : '*.jpg;*.png',
                     id            : 'fileInput',
                     fileObjName   : 'file',
-                    fileSizeLimit : 204800,
+                    fileSizeLimit : 5242880,
                     buttonText    : '选择上传文件',
                     auto          : false,
                     multi         : false,

+ 3 - 1
src/main/resources/static/www/bcrc-mobile/css/bcrc-phone-page.css

@@ -909,10 +909,12 @@
 .list3 h5 b {
 	font-size:1em;
 	margin-right: 15px;
+	display: block;
 }
 .list3 h5 .z_tit {
 	font-size: 1em;
 	color: #343434;
+	display: block;
 }
 .list3 p {
 	/* line-height:2em; */
@@ -1135,7 +1137,7 @@
 .gjrcb_cont dd .ryxx a .jbxx span{ margin:0 3% 0 0; }
 .gjrcb_cont dd .ryxx a p{ font-size:1em; line-height:30px; color:#333;}
 .gjrcb_cont dd .ryxx a .qztj{ font-size:1em; color:#666;}
-.gjrcb_cont dd .ryxx a .qztj span{line-height:30px;}
+.gjrcb_cont dd .ryxx a .qztj span{line-height:30px;display: block;}
 
 
 .bysjynav{ position:relative; height:39px !important;}

+ 1 - 1
src/main/resources/static/www/bcrc/css/bcrc-page.css

@@ -1226,7 +1226,7 @@
     line-height: 35px;
     width: 100%;
 }
-.sy_wz p img{height: auto !important; width: 90% !important;  margin: 0 auto;  display: block !important;}
+.sy_wz p img{ margin: 0 auto;  display: block !important;}
 .sy_wz p a{color: #007eac;}
 .sywzy_xbt em{ float:right; margin:0 20px 0 0;}
 .sywzy_xbt em a{ color:#666; font-size:14px; margin:0 5px;}

File diff suppressed because it is too large
+ 1345 - 0
src/main/resources/static/www/bcrc/css/video-js.css


File diff suppressed because it is too large
+ 57694 - 0
src/main/resources/static/www/bcrc/js/video.js


File diff suppressed because it is too large
+ 6410 - 0
src/main/resources/static/www/bcrc/js/videojs-contrib-hls.min.js


+ 14 - 0
src/main/resources/templates/cms/content_input.html

@@ -238,6 +238,20 @@
                      data-multi="false"
                      data-on-upload-success="${filed.filedName!}_upload_success"
                      data-icon="cloud-upload"></div>
+                <!--下方为大文件FTP上传
+                <div  data-toggle="upload" data-uploader="${ctxPath}/ftpuploads"
+                     data-file-size-limit="1024000000"
+                     data-file-type-exts="${isNotEmpty(str)?strutil.subStringTo(str,0,strutil.length(str)-1):'*.jpg;*.png;*.gif;*.mpg;*.docx;*.doc;*.xls;*.mp4;'}"
+                     data-multi="false"
+                     data-on-upload-success="${filed.filedName!}_upload_success"
+                     data-icon="cloud-upload"></div>-->
+                下方为大文件切片上传
+                <div  data-toggle="upload" data-uploader="${ctxPath}/qpupload"
+                      data-file-size-limit="1024000000"
+                      data-file-type-exts="${isNotEmpty(str)?strutil.subStringTo(str,0,strutil.length(str)-1):'*.jpg;*.png;*.gif;*.mpg;*.docx;*.doc;*.xls;*.mp4;'}"
+                      data-multi="false"
+                      data-on-upload-success="${filed.filedName!}_upload_success"
+                      data-icon="cloud-upload"></div>
                 <span>
                    <input type="text"  class="input-nm" style="margin: 5px 0 0 0"    size="50" name="${filed.filedName!}" placeholder="${filed.alias!}" value="${(!has(content)?'':content[filed.filedName]!),xss='escape'}" id="${filed.filedName!}_file">
                 </span>

+ 2 - 0
src/main/resources/templates/www/syrc-mobile/jlzx-gsxq.html

@@ -99,6 +99,8 @@
 				<p style="white-space: pre;white-space: pre-line;word-wrap: break-word;text-indent: 2em;" id="qy_qyjl">${model.qy_qyjl}</p>
 				<h4 class="gsxx_tit">公司地址</h4>
 				<p>${model.qy_xxdz}</p>
+				<h4 class="gsxx_tit">联系方式</h4>
+				<p style="padding: 0 0 20px 0;border-bottom: solid 1px #ccc;">联系人:${model.qy_lxr} <br> 联系电话:${model.qy_lxdh} </p>
 				<h4 class="gsxx_tit">招聘职位</h4>
 				@for(list in lists){
 				<div class="list3">

+ 2 - 2
src/main/resources/templates/www/syrc-mobile/jlzx-gwxq.html

@@ -120,8 +120,8 @@
 				<p>${list.zw_jnyq}</p>
 				<h4 class="gsxx_tit">工作地址</h4>
 				<p>${list.zw_gzdz}</p>
-				<!--<h4 class="gsxx_tit">公司信息</h4>
-				<p style="white-space: pre;white-space: pre-line;word-wrap: break-word;text-indent: 2em;" id="qy_qyjl">${qy.qy_qyjl}</p>-->
+				<h4 class="gsxx_tit">联系方式</h4>
+				<p style="padding: 0 0 20px 0;border-bottom: solid 1px #ccc;">联系人:${qy.qy_lxr} <br> 联系电话:${qy.qy_lxdh} </p>
 				<h4 class="gsxx_tit">招聘职位</h4>
 				@for(list1 in lists){
 				<div class="list3">

+ 4 - 4
src/main/resources/templates/www/syrc-mobile/qyzx-ssrc.html

@@ -370,11 +370,11 @@
 								</span></div>
 						<div class="clear"></div>
 						<div class="qztj">
-							<span class="fl">求职岗位:${list.qzyx.qzyxZw}</span>
-							<span class="fr">求职性质:${list.qzyx.qzyxHy}</span>
+							<span >求职岗位:${list.qzyx.qzyxZw}</span>
+							<span >求职性质:${list.qzyx.qzyxHy}</span>
 							<div class="clear"></div>
-							<span class="fl">期望薪水:${list.qzyx.qzyxQwxz}</span>
-							<span class="fr">期望地区:${list.qzyx.qzyxDd}</span>
+							<span >期望薪水:${list.qzyx.qzyxQwxz}</span>
+							<span >期望地区:${list.qzyx.qzyxDd}</span>
 						</div>
 						<div class="clear"></div>
 						<!--<p>${list.qzyx.qzyxZwpj}</p>-->

+ 3 - 3
src/main/resources/templates/www/syrc-mobile/wlzp.html

@@ -288,7 +288,7 @@
                             @}
                     >${list.zw_zwmc}</a>
                 </span><a class="gs_tit fr" href="${ctxPath}/qyzx/qyXq?qy_id=${list.qy_id!}">${list.qy_qymc}</a></h4>
-                <h5><b class="red fl">
+                <h5><b class="red">
                     @if(list.zw_yxfw==0){
                     1000元以下
                     @}
@@ -328,7 +328,7 @@
                     @else if(list.zw_yxfw==12){
                     100000元以上
                     @}
-                </b> <span class="fl z_tit">
+                </b> <span class="z_tit">
                     ${strutil.length(list.qy_xxdz!)>40?strutil.subStringTo(list.qy_xxdz!,0,15)+"...":list.qy_xxdz!} |
 					 @if(list.zw_gznx==0){
 					  经验不限
@@ -377,7 +377,7 @@
 					  高中以下
 					  @}
                 </span><span
-                        class="fr z_tit">
+                        class="z_tit">
                     @if(list.qy_jjlx==0){
 				      国有企业
 				      @}

+ 3 - 1
src/main/resources/templates/www/syrc/jlzx-gsxq.html

@@ -101,7 +101,9 @@
 				<h4 class="gsxx_tit">公司简介</h4>
 				<p style="white-space: pre;white-space: pre-line;word-wrap: break-word;text-indent: 2em;" id="qy_qyjl">${model.qy_qyjl}</p>
 				<h4 class="gsxx_tit">公司地址</h4>
-				<p style="padding: 0 0 20px 0;border-bottom: solid 1px #ccc;">${model.qy_xxdz}</p>
+				<p>${model.qy_xxdz}</p>
+				<h4 class="gsxx_tit">联系方式</h4>
+				<p style="padding: 0 0 20px 0;border-bottom: solid 1px #ccc;">联系人:${model.qy_lxr} <br> 联系电话:${model.qy_lxdh} </p>
 				<h4 class="gsxx_tit">招聘职位</h4>
 				@for(list in lists){
 				<div class="list3">

+ 3 - 3
src/main/resources/templates/www/syrc/jlzx-gwxq.html

@@ -119,9 +119,9 @@
 					<h4 class="gsxx_tit">技能要求</h4>
 					<p>${list.zw_jnyq}</p>
 					<h4 class="gsxx_tit">工作地址</h4>
-					<p style="padding: 0 0 20px 0;border-bottom: solid 1px #ccc;">${list.zw_gzdz}</p>
-					<!--<h4 class="gsxx_tit">公司信息</h4>
-					<p style="white-space: pre;white-space: pre-line;word-wrap: break-word;text-indent: 2em;" id="qy_qyjl">${qy.qy_qyjl} </p>-->
+					<p >${list.zw_gzdz}</p>
+					<h4 class="gsxx_tit">联系方式</h4>
+					<p style="padding: 0 0 20px 0;border-bottom: solid 1px #ccc;">联系人:${qy.qy_lxr} <br> 联系电话:${qy.qy_lxdh} </p>
 					<h4 class="gsxx_tit">招聘职位</h4>
 					@for(list1 in lists){
 					<div class="list3">

+ 64 - 0
src/main/resources/templates/www/syrc/news.html

@@ -9,7 +9,14 @@
 <script src="${resPath}/bcrc/js/jquery-1.7.2.min.js"></script>
 <script src="${resPath}/bcrc/js/TL_Tab.js"></script>
 <script src="${resPath}/bcrc/js/TL_PC_Slider.js"></script>
+    <link href="${resPath}/bcrc/css/video-js.css" rel="stylesheet">
+    <script src='${resPath}/bcrc/js/video.js'></script>
+    <script src="${resPath}/bcrc/js/videojs-contrib-hls.min.js"></script>
+
 </head>
+<style>
+    .video-js .vjs-tech {position: relative !important;}
+</style>
 
 <body>
 <div class="contentbig">
@@ -88,3 +95,60 @@
 
 </body>
 </html>
+<script>
+
+    $(function(){
+        var src=document.getElementById("myVideo").poster;
+        if (/\.m3u8$/.test(src)) { //判断视频源是否是m3u8的格式
+            document.getElementById("myVideo").poster = "";
+            var kuan = $('video').width();
+            var gao = $('video').height();
+            changeVideo(src);
+            $("video").attr("width", kuan + "px");
+            $("video").attr("height", gao + "px");
+            var classmyv = $("#myVideo").attr("class");
+            $("#myVideo").removeClass();
+            document.getElementById("myVideo").poster = "";
+            $("#myVideo").attr("style", "text-align:center;width:" + kuan + "px;height: " + gao + "px");
+            $("#myVideo").attr("class", classmyv + " video-js vjs-default-skin vjs-big-play-centered");
+        }
+    });
+
+    /*var myVideo1 = videojs('myVideo1', {
+        loop: true,
+        controls: true,
+        preload: 'auto',
+        autoplay: true,
+    })*/
+
+
+    var changeVideo = function (vdoSrc) {
+        if (/\.m3u8$/.test(vdoSrc)) { //判断视频源是否是m3u8的格式
+            videojs('myVideo', {
+                loop: true,
+                controls: true,
+                preload: 'auto',
+                autoplay: true,
+            }).src({
+                src: vdoSrc,
+                type: 'application/x-mpegURL' //在重新添加视频源的时候需要给新的type的值
+            })
+        } else {
+           // myVideo1.src(vdoSrc)
+        }
+       // myVideo1.load();
+       // myVideo1.play();
+
+    }
+
+    var changeVideo1 = function (vdoSrc) {
+        if (/\.m3u8$/.test(vdoSrc)) { //判断视频源是否是m3u8的格式
+            $("#myVideo").append('<source src="'+vdoSrc+'" type="application/x-mpegURL" />');
+            changeVideo(vdoSrc);
+        }
+       /* $("#myVideo").load();
+        $("#myVideo").play();*/
+
+    }
+
+</script>