zoukankan      html  css  js  c++  java
  • iOS网络开发-打造自己的视频客户端

    一.展示实现

    效果

        

    客户端:                                      服务器端:

              

    二.创建表

     1 create table CourseVideo
     2 (
     3     VideoID int IDENTITY(1,1)  NOT NULL,    
     4     CourseID int NOT NULL,   5     VideoName varchar(500)  NULL,  
     6     VideoPath [varchar](100) NULL,
     7     VideoImage [varchar](200) NULL,
     8     VideoDes [varchar](200) NULL,
     9    VideoLength int NULL,
    10     primary key(VideoID)
    11 )

      

    添加数据

    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (1, 1, N'数组1_为什么要使用数组.mp4', N'CourseVideo/1.mp4', N'CourseImage/1.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (2, 1, N'数组2_什么是数组', N'CourseVideo/2.mp4', N'CourseImage/2.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (3, 1, N'数组3_数组的分类及特点', N'CourseVideo/3.mp4', N'CourseImage/3.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (4, 1, N'数组4:一维数组的声明', N'CourseVideo/4.mp4', N'CourseImage/4.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (5, 1, N'数组5:一维数组的初始化', N'CourseVideo/5.mp4', N'CourseImage/5.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (6, 1, N'数组6:一维数组的访问(引用)', N'CourseVideo/6.mp4', N'CourseImage/6.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (7, 1, N'数组7:数组的算法:查找', N'CourseVideo/7.mp4', N'CourseImage/7.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (8, 1, N'数组8:数组的算法:排序 (1)', N'CourseVideo/8.mp4', N'CourseImage/8.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (9, 1, N'数组09:二维数组的声明', N'CourseVideo/9.mp4', N'CourseImage/9', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (10, 1, N'数组10:二维数组的初始化', N'CourseVideo/10.mp4', N'CourseImage/10.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (11, 1, N'数组11:二维数组的访问', N'CourseVideo/11.mp4', N'CourseImage/11.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (12, 1, N'数组12:多维数组简介', N'CourseVideo/12.mp4', N'CourseImage/12.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (13, 1, N'数组13:C语言中的字符串', N'CourseVideo/13.mp4', N'CourseImage/13.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (14, 1, N'数组14:字符数组', N'CourseVideo/14.mp4', N'CourseImage/14.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (15, 1, N'数组15:字符串的输入输出', N'CourseVideo/15.mp4', N'CourseImage/15.png', NULL)
    GO
    INSERT [dbo].[CourseVideo] ([VideoID], [CourseID], [VideoName], [VideoPath], [VideoImage], [VideoDes]) VALUES (16, 1, N'数组16:字符串处理函数', N'CourseVideo/16.mp4', N'CourseImage/16.jpg', NULL)
    GO

    记得视频路径勿加中文,否则视频播放不出来

    三.搭建WebService服务器

    1.DatableToList.cs文件用于DataTable转换List<T>

     public class DatableToList 
        {
            public static List<T> ConvertToList<T>(DataTable dt) where T : new()
            {
                //定义集合
                List<T> ts = new List<T>();
    
                //获得此模型的类型
                Type type = typeof(T);
    
                //定义一个临时变量
                string tempName = string.Empty;
    
                //便利DataTable数据行
                foreach (DataRow dr in dt.Rows)
                {
                    T t = new T();
                    //获得此模型的公共属性
                    PropertyInfo[] propertys = t.GetType().GetProperties();
                    
                    //遍历该对象的所有属性
                    foreach(PropertyInfo pi in propertys)
                    {
                        tempName = pi.Name;//将属性名称赋值给临时变量
                        //检查DataTable是否包含此列(列名==对象的属性名)  
                        if (dt.Columns.Contains(tempName))
                        {
                            // 判断此属性是否有Setter
                            if (!pi.CanWrite) continue;//该属性不可写,直接跳出
                            //取值
                            object value = dr[tempName];
                            //如果非空,则赋给对象的属性
                            if (value != DBNull.Value)
                                pi.SetValue(t, value, null);
                        }
                    }
                     //对象添加到泛型集合中
                    ts.Add(t);
                }
                return ts;
            }
         
       
        }

    2.创建Model类库

    CourseVideo.cs类

    public  class CourseVideo
        {
            private int videoID;
    
            public int VideoID
            {
                get { return videoID; }
                set { videoID = value; }
            }
            private int courseID;
    
            public int CourseID
            {
                get { return courseID; }
                set { courseID = value; }
            }
            private String videoName;
    
            public String VideoName
            {
                get { return videoName; }
                set { videoName = value; }
            }
            private String videoPath;
    
            public String VideoPath
            {
                get { return videoPath; }
                set { videoPath = value; }
            }
            private String videoImage;
    
            public String VideoImage
            {
                get { return videoImage; }
                set { videoImage = value; }
            }
        private int videoLength;
          public int VideoLength
            {
                get { return videoLength; }
                set { videoLength = value; }
            }
    }

    3.创建Dal类库

    CourseVideoDal.cs类

    查询CourseVideo表信息

    这是比较简单容易理解的方式,但是字段多的话就很不实用。

    //查询视频资源
            public List<CourseVideo> Select()
            {
                List<CourseVideo> list = new List<CourseVideo>();
                DataTable dt = new DataTable();
                CourseVideo model = null;
                DataBase db = new DataBase();
                String comstr = "select VideoID,CourseID,VideoName,VideoPath,VideoImage,VideoLength from CourseVideo";
                dt = db.GetDataTable(comstr);
                for (int i = 0; i < dt.Rows.Count;i++ )
                {
                    model = new CourseVideo();
                    model.VideoID = Convert.ToInt32(dt.Rows[i][0]);
                    model.CourseID = Convert.ToInt32(dt.Rows[i][1]);
                    model.VideoName = dt.Rows[i][2].ToString();
                    model.VideoPath = dt.Rows[i][3].ToString();
                    model.VideoImage = dt.Rows[i][4].ToString();
              
    model.VideoLength = Convert.ToInt32(dt.Rows[i][5]);
              list.Add(model);
           }
            
    return list;
         }

    之前新建的DatableToList.cs类文件就可以用到了,使用泛型将DataTable数据转换为List<T>

    泛型之前一直没机会用到,于是自己百度学习了一下,封装好DatableToList文件后,很好的提高代码

    了质量,更方便使用。

     //使用泛型 查询视频资源
            public List<CourseVideo> Select2()
            {
                List<CourseVideo> list = new List<CourseVideo>();
                DataTable dt = new DataTable();
                DataBase db = new DataBase();
                String comstr = "select VideoID,CourseID,VideoName,VideoPath,VideoImage,VideoLength from CourseVideo";
                dt = db.GetDataTable(comstr);
                list = DatableToList.ConvertToList<CourseVideo>(dt);
                return list;
    
            }

    4.新建Web 服务

     只需要在App_Code文件夹下找到Service.cs添加

    4.1返回json格式

    添加命名空间:

    using System.Web.Script.Services;
    using System.Web.Script.Serialization;

    还有在方法前面声明

       [WebMethod(Description = "json查询视频资源")]

     [ScriptMethod(ResponseFormat = ResponseFormat.Json)]

     [WebMethod(Description = "json查询视频资源")]
        [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
        public String VideoSelect()
        {
            return new JavaScriptSerializer().Serialize(courseVideoDal.Select());
            //   return dal.Select();
    
        }

    4.1返回xml格式

    [WebMethod(Description = "xml查询视频资源")]
    
    public List<CourseVideo> xmlVideoSelect()
    {
    return courseVideoDal.Select();
    }

    设置外部访问需要在Web.config添加节点:

     <webServices>
            <protocols>
              <add name="HttpSoap" />
              <add name="HttpPost" />
              <add name="HttpGet" />
              <add name="Documentation" />
            </protocols>
          </webServices>

    看下结果

    接下来把项目部署在IIS服务器上即可使用,如何部署我这就不多说了,可以查一下百度

     附件:忘记保存了,这里用到一个工具

    WSDL2ObjC-0.6.zip

     Parse WSDL后稍等15秒左右出现Finish!查看导入目录

    将生成的所有文件放置在wsdl2objc文件夹导入项目中

    尝试编译出现错误如下:1."libxml/tree.h" file not found

    解决办法:

    链接libxml2.2dylib库

    TARGETS -> Build Phases -> Linking Binary With Libraries-> libxml2.2dylib

    TARGETS -> Build Settings -> Search Paths-> Header Search Paths,设置“/usr/include/libxml2”

    TARGETS -> Build Phases -> Compile Sources  将Service.m,USAddition.m,NSDate+ISO8601Unparsing.m,NSDate+ISO8601Parsing.m

    文件 设置不使用ARC   -fno-objc-arc

    手动ARC设置方法如下:

    1.在Compiler Flags一列加上-fno-objc-arc就表示禁止这个.m文件的ARC

    2.在Compiler Flags一列加上-fobjc-arc就表示开启这个.m文件的ARC

    5.创建数据模型

    lmjVideo.h文件

    //视频ID
    @property (assign,nonatomic) int ID;
    
    //视频名称
    @property (copy,nonatomic) NSString *name;
    
    //视频长度
    @property (assign,nonatomic) int length;
    
    //视频图片
    @property (copy,nonatomic) NSString *image;
    
    //视频链接
    @property (copy,nonatomic) NSString *url;
    
    + (instancetype)videoWithDict:(NSDictionary *)dict;

    lmjVideo.m文件

    +(instancetype)videoWithDict:(NSDictionary *)dict
    {
        lmjVideo *video = [[self alloc] init];
        video.name = dict[@"VideoName"];
        video.image = dict[@"VideoImage"];
        video.url = dict[@"VideoPath"];
        video.length = [dict[@"VideoLength"] intValue];
        video.ID = [dict[@"VideoID"] intValue];
        return video;
        
         //    [video setValuesForKeysWithDictionary:dict]; // KVC方法使用前提: 字典中的所有key 都能在 模型属性 中找到
        
    }

    自定义cell,对cell内部数据处理的封装

    lmjVideoCell.h文件

    文件

    @class lmjVideo;
    @interface lmjVideoCell : UITableViewCell
    
    @property (nonatomic,strong) lmjVideo *video;
    + (instancetype)cellWithTableView:(UITableView *)tableView;

    lmjVideoCell.m文件

    #import "lmjVideoCell.h"
    #import "lmjVideo.h"
    #import "UIImageView+WebCache.h"
    #import "UIView+Extension.h"
    @interface lmjVideoCell()
    @property (nonatomic,weak) UIView *driver;
    
    @end
    
    
    @implementation lmjVideoCell
    
    + (instancetype)cellWithTableView:(UITableView *)tableView
    {
        static NSString *ID = @"video";
        lmjVideoCell *cell = [tableView dequeueReusableCellWithIdentifier:ID];
        if (!cell)
        {
            cell = [[lmjVideoCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:ID];
        }
        return cell;
    }
    
    
    
    - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
    {
        self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
        
        if (self) {
            UIView *driver = [[UIView alloc] init];
            driver.backgroundColor = [UIColor lightGrayColor];
            driver.alpha = 0.2;
            [self.contentView addSubview:driver];
            self.driver = driver;
            
            
        }
        
        return self;
    }
    
    - (void)setVideo:(lmjVideo *)video
    {
        _video = video;
        
        self.textLabel.text = video.name;
        self.detailTextLabel.text = [NSString stringWithFormat:@"时长:%d分钟",video.length];
        
        NSString *imageUrl = [NSString stringWithFormat:@"http://180.84.33.156:8882/%@",video.image];
        [self.imageView setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"placeholder"]];
    }
    
    - (void)layoutSubviews
    {
        [super layoutSubviews];
        
        //调整子控件的frame
        CGFloat imageX = 10;
        CGFloat imageY = 10;
        CGFloat imageH = self.height - 2 * imageY;
        CGFloat imageW = imageH * 200 / 112;
        self.imageView.frame = CGRectMake(imageX, imageY, imageW, imageH);
        
        self.textLabel.x = CGRectGetMaxX(self.imageView.frame) + 10;
        
        self.detailTextLabel.x = self.textLabel.x;
        
        CGFloat driverH = 1;
        CGFloat driverY = self.height - driverH;
        CGFloat driverW = self.width;
        self.driver.frame = CGRectMake(0, driverY, driverW, driverH);
    
    }

    分类

    UIView+Extension.h文件

    添加一个UIView的分类,直接修改UI控件的x值

    @property (nonatomic,assign) CGFloat x;
    @property (nonatomic,assign) CGFloat y;
    @property (nonatomic,assign) CGFloat width;
    @property (nonatomic,assign) CGFloat height;

    UIView+Extension.m文件

    #import "UIView+Extension.h"
    
    @implementation UIView (Extension)
    
    - (void)setX:(CGFloat)x
    {
        CGRect frame = self.frame;
        frame.origin.x = x;
        self.frame = frame;
    }
    
    - (CGFloat)x
    {
        return self.frame.origin.x;
    }
    
    - (void)setY:(CGFloat)y
    {
        CGRect frame = self.frame;
        frame.origin.y = y;
        self.frame = frame;
    }
    
    - (CGFloat)y
    {
        return self.frame.origin.y;
    }
    
    - (void)setWidth:(CGFloat)width
    {
        CGRect frame = self.frame;
        frame.size.width = width;
        self.frame = frame;
        
    }
    
    - (CGFloat)width
    {
        return self.frame.size.width;
    }
    
    - (void)setHeight:(CGFloat)height
    {
        CGRect frame = self.frame;
        frame.size.height = height;
        self.frame = frame;
    }
    - (CGFloat)height { return self.frame.size.height; } @end

    实现“视屏列表界面只支持竖屏方向

    自定义lmjNavigationController控制器,其继承自UINavigationController

       UIInterfaceOrientationMaskPortrait:竖屏(正常)
       UIInterfaceOrientationMaskPortraitUpsideDown:竖屏(上下颠倒)
       UIInterfaceOrientationMaskLandscapeLeft:横屏向左
       UIInterfaceOrientationMaskLandscapeRight:横屏向右
       UIInterfaceOrientationMaskLandscape:横屏(左右都支持)
       UIInterfaceOrientationMaskAll:所有都支持
       

    lmjNavigationViewController.m

    #import "lmjNavigationViewController.h"
    
    @interface lmjNavigationViewController ()
    
    @end
    
    @implementation lmjNavigationViewController
    
    //控制当前控制器支持那些方向
    
    -(NSUInteger)supportedInterfaceOrientations
    {
      //竖屏 
    return UIInterfaceOrientationMaskPortrait; } @end

    自定义lmjMoviePlayerViewController控制器,继承MPMoviePlayerViewController

    导入MediaPlayer.framework框架,lmjMoviePlayerViewController.h在添加头文件 

    #import <MediaPlayer/MediaPlayer.h>

    lmjMoviePlayerViewController.m

    #import "lmjMoviePlayerViewController.h"
    
    @interface lmjMoviePlayerViewController ()
    
    @end
    
    @implementation lmjMoviePlayerViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        
        // 移除程序进入后台的通知
        [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
    }
    
    #pragma mark - 实现这个方法来控制屏幕方向
    /**
     *  控制当前控制器支持哪些方向
     *  返回值是UIInterfaceOrientationMask*
     */
    - (NSUInteger)supportedInterfaceOrientations
    {
        return UIInterfaceOrientationMaskLandscape;
    }

    @end

    6.主控制器文件代码:

    需要注意的是,视频播放的文件路径勿加中文,否则视频不能播放

    //
    //  lmjViewController.m
    //  橙子视频客户端
    //
    //  Created by lmj on 15-6-24.
    //  Copyright (c) 2015年 lmj. All rights reserved.
    //
    
    #import "lmjViewController.h"
    #import "MBProgressHUD+MJ.h"
    #import "lmjVideo.h"
    #import "UIImageView+WebCache.h"
    #import "lmjMoviePlayerViewController.h"
    #import "lmjVideoCell.h"
    #import "Service.h"
    #define strUrl @"http://180.84.33.156:8882"
    @interface lmjViewController ()
    //所有视频的集合
    @property (nonatomic,strong) NSArray *videos;
    @end
    
    @implementation lmjViewController
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        [MBProgressHUD showMessage:@"正在加载视频信息..."];
        NSString *result;
        NSData *data;
        ServiceSoap *binding = [Service ServiceSoap];
        Service_VideoSelect  *request = [[Service_VideoSelect  alloc] init];
        ServiceSoap12Response *response = [binding  VideoSelectUsingParameters:request];
        for(id mine in response.bodyParts){
            if([mine isKindOfClass:[Service_VideoSelectResponse class]])
            {
             //   [request  release];
                [MBProgressHUD hideHUD];
                
                result = [mine VideoSelectResult];
                data = [result dataUsingEncoding:NSUTF8StringEncoding];
                if(data)
                {
              //  NSLog(@"data----%@",data);
                    NSArray *array =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:nil];
                    NSMutableArray *videos = [NSMutableArray array];
                    for (NSDictionary *dict in array) {
                    lmjVideo *video = [lmjVideo videoWithDict:dict];
                    [videos addObject:video];
                    NSLog(@"%@",video.url);
                    }
                    self.videos = videos;
                    [self.tableView reloadData];
                }
                else{
                    [MBProgressHUD showError:@"网络繁忙"];
                }
    
            //     NSLog(@"ns----%@",ns);
          //     NSDictionary *dict= [NSJSONSerialization JSONbjectWithData:data  options:NSJSONReadingAllowFragmentS error:nil];
                
                
            }
        }
       
    }
    #pragma mark -数据源
    -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
        return self.videos.count;
    }
    
    -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        lmjVideoCell *cell = [lmjVideoCell cellWithTableView:tableView];
        cell.video = self.videos[indexPath.row];
        return cell;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
    {
        return 70;
    }
    
    -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    {
        lmjVideo *video = self.videos[indexPath.row];
        
        //播放视频
        NSLog(@"%@",video.url);
        NSString *videoUrl = [NSString stringWithFormat:@"http://180.84.33.156:8882/%@",video.url];
        lmjMoviePlayerViewController *playerVc = [[lmjMoviePlayerViewController alloc] initWithContentURL:[NSURL URLWithString:videoUrl]];
        
    
        [self presentMoviePlayerViewControllerAnimated:playerVc] ;   //全拼播放
    }
    
    @end
  • 相关阅读:
    【luogu3768】简单的数学题 欧拉函数(欧拉反演)+杜教筛
    【codeforces666E】Forensic Examination 广义后缀自动机+树上倍增+线段树合并
    【bzoj5073】[Lydsy1710月赛]小A的咒语 后缀数组+倍增RMQ+贪心+dp
    【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理
    窗体的呈现、用户控件的呈现
    WPF和js交互 WebBrowser数据交互
    字符串string 转换为 Base64String
    静态资源加载过程及时序
    if else 与 if else if 的区分与使用总结
    复杂耗时逻辑处理——子线程
  • 原文地址:https://www.cnblogs.com/linmingjun/p/4606451.html
Copyright © 2011-2022 走看看