angularjs和ajax的结合使用 (四)
知道的朋友了解 我不是属于讲按部就班技术的那种人。什么xx入门 ,入门到精通,入门到入土。 其实非要严格说的话已经跟angularjs 什么ajax 偏的有点远了,之所以还是叫这个名称,因为都属于web应用 ,叫这个名称是一种延续,其实这个系列持续了几年了 是我自己从学习到一种适合我自己环境的特有应用方式的一种总结。主题还是一个:web应用,往细了装逼了说一种同时适合web 和winform 客户端 独到的 数据架构 处理方式。当然所有的都是基于以前的基础之上的。
主题:一种同时适合web 和winform 客户端 独特的 数据架构 处理方式
后台API权限控制
首先是后台的接口 ,使用webapi的方式 返回 json 数据 。当然这里有一个技巧 , 也就是权限控制。众所周知 http 有一种 方式 可以把授权放在header 里。后台验证 ,每个接口都要权限符合才能 请求到数据。都知道asp.net MVC有filter 可以用来先进行过滤 ,都在Java做web后台满大街 的年代 我们还在用中古时期的ASP.Net MVC。首先我们对后台代码和web部分进行了分层,数据访问对象为Entity ,controllers 为各个请求的API web的和winform的在一起,我们依旧使用了简单的三层架构,xxxLogic.cs 其实是实际的业务逻辑代码:
所有的是基于WebAPI形式的 老套路在初始化时进行 router注册 以便让请求映射到对应的controller 不用多说了,还有是asp.net MVC是可以配置返回数据格式为xml 或者json的。
1 public class Global : System.Web.HttpApplication
2 {
3
4 protected void Application_Start(object sender, EventArgs e)
5 {
6
7 AreaRegistration.RegisterAllAreas();
8 //GlobalConfiguration.Configuration.ParameterBindingRules.
9 // Insert(0,SimplePostVariableParameterBinding.HookupParameterBinding);
10 WebApiConfig.Register(GlobalConfiguration.Configuration);
11 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
12 RouteConfig.RegisterRoutes(RouteTable.Routes);
13 }
14
15 protected void Session_Start(object sender, EventArgs e)
16 {
17
18 }
19 protected void Application_BeginRequest(object sender, EventArgs e)
20 {
21 if (Context.Request.FilePath == "/") Context.RewritePath("Default.aspx");
22 }
23
24
25
26 public override void Init()
27 {
28 PostAuthenticateRequest += WebApiApplication_PostAuthenticateRequest;
29
30 base.Init();
31 }
32 void WebApiApplication_PostAuthenticateRequest(object sender, EventArgs e)
33 {
34 HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
35 }
36 }
1 public class RouteConfig
2 {
3 public static void RegisterRoutes(RouteCollection routes)
4 {
5 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
6
7 routes.MapRoute(
8 name: "Default",
9 url: "{controller}/{action}/{id}",
10 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
11 );
12 }
13 }
1 public static class WebApiConfig
2 {
3 public static void Register(HttpConfiguration config)
4 {
5 System.Web.Mvc.ValueProviderFactories.Factories.Add(new System.Web.Mvc.JsonValueProviderFactory());
6 //下面这句务必加上 否则就只能在IE下才能得到正确的json数据
7 //必须要添加http.formating 那个dll的引用
8 GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
9 //GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
10 config.Routes.MapHttpRoute(
11 name: "DefaultApi",
12 routeTemplate: "api/{controller}/{action}/{id}",
13 defaults: new { controller = "Home", action = "Index", id = RouteParameter.Optional }//new { id = RouteParameter.Optional }
14 );
15
16 }
17 }
来看下我们的后台进行权限控制的代码,我们并未进行复杂的权限控制 仅仅只是判断登录:
1 public class Power : System.Web.Http.Filters.ActionFilterAttribute
2 {
3 public Power(string actioinName)
4 {
5
6 }
7 public override void OnActionExecuting(HttpActionContext actionContext)
8 {
9 HttpRequest request = HttpContext.Current.Request;
10 string username = request.Headers["username"];
11 string password = request.Headers["password"];
12
13
14 LicWebUtil util = new LicWebUtil();
15 var loginuser = util.loginNormal(username, password);
16 if (loginuser==null)
17 {
18 throw new Exception("未登录啊");
19 }
20 }
21 }
数据处理
然后是数据处理,我们在服务端构建了统一的数据格式APIResult:
1 public class APIResult
2 {
3 public bool Success { get; set; }
4 public object Data { get; set; }
5
6 public string Msg { get; set; }
7
8 }
web端的 通用 js请求 ,get和post 注意promise 应用的机巧 ,以及提交时在登录成功了的情况下 会自动往header里加权限 。
1 var app = angular.module("scpSite", ["ui.router"]);
2
3 //注入一个util 工具类
4 app.service("Util", function ($http, $rootScope, $q, $compile) {
5
6 var boxPromise = function (promise) {
7 var myPromise = {
8 prom: promise,
9 then: function (fun1, fun2) {
10 promise.then(function (response) {
11 //response.status==200// response.status==500 这里就不使用这种方式判断了
12 if (response && response.data && response.data.Success) {
13 fun1(response);
14 }
15 else {
16 //服务端有正常的错误消息返回
17 if (response && response.data && response.data.Success == false) {
18 alert("获取数据失败:" + response.data.Message);
19 }
20 //throw exception 500错误
21 else {
22 alert("获取数据失败:" + response.data.ExceptionMessage);
23 }
24
25 if (fun2 != undefined)
26 fun2(response);
27 }
28 }, function () {//在刚httpget的时候可以 而在此处根本就不会执行此函数
29 });
30 }
31 };
32 return myPromise;
33 };
34
35 var _this = {
36 get: function (path, _params) {
37 var promise;
38 if (_params != undefined && _params != null) {
39 promise = $http.get(path, { headers: { username: $rootScope.username, password: $rootScope.password }, params: _params }).then(function (response) {
40 return response;
41 }, function (response) {
42 return response;
43 });
44 } else {
45 promise = $http.get(path, { headers: { username: $rootScope.username, password: $rootScope.password } }).then(function (response) {
46 return response;
47 }, function (response) {
48 return response;
49 });
50 }
51 return boxPromise(promise);
52 },
53 post: function (url, data) {
54 var promise;
55 if (data != undefined && data != null) {
56 promise = $http.post(url,data , { headers: { username: $rootScope.username, password: $rootScope.password }}).then(function (response) {
57 return response;
58 }, function (response) {
59 return response;
60 });
61 } else {
62 promise = $http.post(url, { headers: { username: $rootScope.username, password: $rootScope.password } }).then(function (response) {
63 return response;
64 }, function (response) {
65 return response;
66 });
67 }
68 return boxPromise(promise);
69 }
70
71 }
72
73 return _this;
74
75 });
然后是登录 ,登录成功了 angularjs 全局变量就会有用户信息 ,提交时post就会自动往权限里加。结合上面的一起运作 ,体会一下这样设计 以及联动运作的精妙之处,并且如果服务端有错误 在post之初就会自动报出错误 并且利用promise的机制 自动阻断 不让执行进程传到下层 不让逻辑往后走,如果数据成功 则会自动调用下层promise的数据展现操作进行页面渲染,这样来达到规范化:
1 app.controller("MainController", function ($rootScope, $scope, $rootScope, $stateParams, $state, Util) {
2
3 $rootScope.loginok = false;
4
5 $scope.username = "";
6 $scope.password = "";
7
8 $rootScope.username = "";
9 $rootScope.password = "";
10
11 //登录测试 否则弹出登录对话框
12 $scope.loginTest = function () {
13
14 if ($scope.loginok == false) {
15 $('#myModal').modal({ backdrop: 'static', keyboard: false, show: true });
16 }
17 }
18
19 $scope.login = function () {
20
21 Util.get("/api/Util/login", { username: $scope.username, password: $scope.password }).then(function (res) {
22 if (res.data.Data==null||res.data.Data == "") {
23 alert("登录失败");
24 }
25 else {
26 alert("登录成功");
27 $rootScope.username = $scope.username;
28 $rootScope.password = $scope.password;
29 $rootScope.loginok = true;
30
31
32 $('#myModal').modal('hide');
33 }
34 }, function (res) {
35 alert("登录遇到错误");
36 });
37
38
39 }
40
41 $scope.copyrightEndYear = "2018";
42 $scope.GetCopyrightEndYear = function () {
43 Util.get("/api/Util/GetCopyrightEndYear").then(function (res) {
44 $scope.copyrightEndYear = res.data.Data;
45 });
46 }
47 $scope.GetCopyrightEndYear();
48 });
如果登录成功后那么后续就是简单的平铺直述的调用了,下面是一个简单的示例。
1 app.controller("DefaultController", function ($scope, Util) {
2 $scope.newsList = [];
3 $scope.inititalData = function () {
4 Util.get("/api/CMS/GetContentByCategory", { category: "新闻中心", top: 5, getContent: false }).then(function (res) {
5 $scope.newsList = res.data.Data;
6 });
7 }
8 $scope.inititalData();
9 });
看下我们的使用效果
不用想当然的在客户端调试把mask去掉以为就可用了哈,我们是做了完善的后台校验机制的。
同一接口应用于winform端
看,跟上面相结合的统一处理 WebAPI promise post 的结合应用正是这个框架的优雅之处 ,并且 APIResult格式 是统一的 在winform客户端只要实现一个json解析 ,同一个接口或者业务逻辑就可应用于Windows客户端了 就这样简单的就达到了同步。关于winform 接口 结果数据的处理,很简单 我们构建一个跟json一致c#的类 反序列化即可。这是winform 构造出的请求 和其他代码,注意我们是用上面同一规格APIResult 来进行json解析的,通过httprequest 请求 ,原先设计的我们有广告 也就是图片 还有文本。那么应该怎么处理呢? 不是有泛型吗? 看我的:注意泛型的应用 ,如果是img则转而使用stream解析,普通的则使用APIResult 解析出文本。
1 public static T DownloadSomething<T>(string url,string appendUrl,Dictionary<string,string> pars)
2 {
3 try
4 {
5 if (string.IsNullOrEmpty(appendUrl) == false)
6 {
7 url += appendUrl;
8 }
9
10 if (pars != null)
11 {
12 var enumer = pars.GetEnumerator();
13 int parIndex = 0;
14 while (enumer.MoveNext())
15 {
16 if (parIndex == 0)
17 {
18 url += string.Format("?{0}={1}", enumer.Current.Key, enumer.Current.Value);
19 }
20 else
21 {
22 url += string.Format("&{0}={1}", enumer.Current.Key, enumer.Current.Value);
23 }
24 parIndex++;
25 }
26 }
27
28 HttpWebRequest rq = (HttpWebRequest)WebRequest.Create(url);
29 rq.Headers["Accept-Encoding"] = "utf-8";
30
31 if (WriterRuntime.loginUser != null && string.IsNullOrEmpty(WriterRuntime.loginUser.UserNameOrHardwareID) == false)
32 {
33 rq.Headers["username"] = WriterRuntime.loginUser.UserNameOrHardwareID;
34 rq.Headers["password"] = WriterRuntime.loginUser.Password;
35 }
36 rq.Method = "GET";
37 rq.Timeout = 10000;//2秒超时
38 T retData = default(T);
39
40 HttpWebResponse rc = (HttpWebResponse)rq.GetResponse();
41 Stream stream = rc.GetResponseStream();
42 StreamReader sr = new StreamReader(stream, Encoding.UTF8);
43
44
45 if (typeof(T) == typeof(Image))
46 {
47 retData = (T)(object)Image.FromStream(stream);
48 }
49 else
50 {
51 APIResult apiResult = JsonConvert.DeserializeObject<APIResult>(sr.ReadToEnd());
52
53 if (apiResult.Data != null)
54 {
55 if ((typeof(T) == typeof(string)))
56 {
57 retData = (T)(object)apiResult.Data;
58 }
59 else if ((typeof(T) == typeof(Int64)))
60 {
61 retData = (T)(object)apiResult.Data;
62 }
63 else if((typeof(T) == typeof(bool))){
64 retData = (T)(object)apiResult.Data;
65 }
66 else
67 {
68 retData = ((Newtonsoft.Json.Linq.JObject)apiResult.Data).ToObject<T>();
69 }
70
71 }
72 }
73
74 sr.Close();
75 rc.Close();
76
77 if (typeof(T) == typeof(string))
78 {
79 return retData;
80 }
81 else if (typeof(T) == typeof(Image))
82 {
83 return retData;
84 }
85 else
86 {
87 return retData;
88 }
89
90 }
91 catch (Exception ex)
92 {
93 MessageBox.Show("与服务器连接失败");
94 Application.Exit();
95 }
96 return default(T);
97 }
还有,我们的客户端是支持升级的,固定的连接上服务器后先进性API版本校验 ,如果校验失败 会强迫客户端进行版本更新。强不强迫客户端更新的决定权在我们 只要把服务端的ver接口数字调高 就可以把低于某版本的客户端淘汰掉了。看资本的力量如此强大 ,这不就像手机上的某某xxAPP吗 其实啥实质功能都没更新 ,更新了一堆的广告。
1 private void LoginForm_Load(object sender, EventArgs e)
2 {
3
4 //先进行联网和版本检测 失败则退出
5 Int64 serverVer = USBKeyWriterUtil.DownloadSomething<Int64>(WriterRuntime.apiUrl, "Util/ClientAPI_Ver", null);
6 if (serverVer > WriterRuntime.ver)
7 {
8 USBKeyWriter.UI.Upgrade uDlg = new USBKeyWriter.UI.Upgrade();
9 uDlg.ShowDialog(this);
10 return;
11 }
12 Process[] app = Process.GetProcessesByName("NewScp");
13 if (app.Length > 0)
14 {
15 MessageBox.Show("请先退出Dicom打印服务软件,再运行此授权机程序。");//请先退出Dicom打印服务软件(任务管理器NewScp进程)再运行此授权机程序
16 Application.Exit();
17 return;
18 }
19
20 //初始化runtime
21 rt = WriterRuntime.GetInstance();
22 rt.Initial();
23
24 string deviceUserName = USBKeyWriterUtil.getDefaultLoginId();
25 if (string.IsNullOrEmpty(deviceUserName))
26 {
27 tbxuname.Text = "admin";
28 }
29 else
30 {
31 tbxuname.Text = deviceUserName;
32 }
33 }
好了 全部 结束 ,感谢各位看官观赏,周末愉快。
angularjs和ajax的结合使用 (四)的更多相关文章
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
Django基础七之Ajax 本节目录 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) 一 Ajax简介 ...
- 如何使用angularjs实现ajax异步请求
Sample.html <!DOCTYPE html> <html ng-app="myApp"> <head> <title>fo ...
- {Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解)
{Django基础七之Ajax} 一 Ajax简介 二 Ajax使用 三 Ajax请求设置csrf_token 四 关于json 五 补充一个SweetAlert插件(了解) Django基础七之 ...
- angularjs和ajax的结合使用 (一)
好久没写文了.这是一篇关于easyui配合ajax使用 的文章, 顺带介绍angularjs的使用 以及让你感受到angularjs的威力.网上对于ajax 的文也是多如牛毛 .我就不直接 从那种原生 ...
- angularJS项目-ajax事件的按钮loading和页面loading状态 & Controller之间通信-待续
1).按钮loading --TODO 2). page loading状态 1.在module中注入指令 // Route State Load Spinner(used on page or co ...
- angularjs和ajax的结合使用 (三)
转眼九月份了,忙忙碌碌 发现今年还没开过张,写一篇吧. 15年在空闲时就倒腾过angularjs那玩意儿 ,觉得还是挺好的,李金龙那厚厚的一本书,只不过没有系统化应用.最主要的是原来有一个东西没有用到 ...
- angularjs之$ajax请求
AngularJS不仅仅只有双向绑定等等功能,还有发送Ajax请求的Api. 效果图: 请求的文件(data.php): <?php $data = [ '股市下跌', '清明小长假结束', ' ...
- angularjs 发送ajax请求的问题
在angularjs中使用 ajax 如果使用 jquery的 ajax发送请求会遇到结果返回了,但是页面的值却没有改变,如: $scope.queryNameMatch = function() { ...
- angularjs和ajax的结合使用 (二)
今天我们来继续丰富上次的例子.我们来搞些 稍微复杂点的应用. 首先我们来加一个全选 的功能. 上一篇的例子里我们看到 分页时载入的是我们通过linq 查询自定义列 然后构建的匿名类 .使用这种EF框架 ...
- Angularjs之controller 和filter(四)
Controller组件(http://www.angularjs.cn/A00C) 在AngularJS中,控制器是一个Javascript函数(类型/类),用来增强除了根作用域以外的作用域实例的. ...
随机推荐
- mysql8创建用户
create user test_user@'%' identified by 'test2022@'; grant all privileges on test.* to test_user@'%' ...
- Java 技术,IBM 风格: 类共享
共享类特性帮助减少内存占用并改进启动性能 Java 5.0 平台的 IBM 实现中新的共享类特性提供了一种完全透明和动态的方法,可以共享已经装载的所有类,而不会对共享类数据的 JVM 施加限制.这个特 ...
- python项目依赖管理之poetry
poetry,是一个强大的Python项目依赖管理工具,旨在简化和优化项目的依赖管理过程.它提供了一种简单且一致的方式来定义.安装和管理项目所需的依赖项.本文将详细介绍poetry库的安装方法.使用方 ...
- golang工具之generate
示例: 大家经常碰到命名错误码.状态码的同时,又要同步写码对应的翻译,有没有感觉很无聊.这里举一个例子: package main import "fmt" // 定义错误 ...
- SPRING 动态注册BEAN
场景 有些情况下,不能直接使用BEAN的方式: @Bean(name = "storage") public DataSourceProxy storageDataSourcePr ...
- Vite项目无法通过IP+端口的方式访问开发服务
前情 最近要新开一个项目,技术栈由自己安排,于是就想到使用vue3+vite来做,体验一把新技术栈 坑位 vite开发体验极佳,但是在项目完成的时候,想通过本地服务提前发给产品确认UI.交互等细节的时 ...
- PDFSharp 1.5 更新
PDFsharp 1.50 Preview Information - PDFsharp & MigraDoc PDFShapr 1.50 修复与改进 支持 Object Streams - ...
- 使用 VS Code 徒手构建 PDF 文件
使用 VS Code 徒手构建 PDF 文件 PDF 文件是广泛应用的页面描述文件格式,从本质上讲,文件内部的结构混合使用了文本格式描述和二进制格式描述,对于简单的文件,比如说我们今天要创建的第一个 ...
- NoSQL 述评
作为主库的 nosql 只有 CockroachDB.TiKV 以及 MongoDB(从4.0后事务似乎可用了),CockrouchDB 已经收费,另外 YugabyteDB 也可选,但大家的反馈都不 ...
- Qt编写安防视频监控系统37-onvif预置位
一.前言 预置位在视频监控系统中是不可或缺的存在,响应预置位功能的前提是要带预置位的云台球机,有些普通的云台球机其实不带预置位的,这个要检查清楚,硬件上不支持该功能的,你再怎么点也没反应.在这个视频监 ...