ASP.NET中进行消息处理(MSMQ) 二

在我上一篇文章《ASP.NET中进行消息处理(MSMQ)一》里对MSMQ做了个通俗的介绍,最后以发送普通文本消息和复杂的对象消息为例介绍了消息队列的使用。 本文在此基础上继续介绍MSMQ的相关知识点,最后还是通过一个示例程序来分析MSMQ在实际项目开发中的应用。

建议:如果你对MSMQ不够了解,在你阅读本文前请先阅读第一部分:《ASP.NET中进行消息处理(MSMQ)一》。

一、消息传递的优先级
      在MSMQ中消息在队列里传输是分有优先级的,这里我就以实例的形式介绍下关于优先级的使用,优先级一共有七种,MessagePriority枚举里全部进行了封装。因这里只作程序演示就不一一列举出,仅用了HighestNormal两种类型,关于消息队列上进行消息传输的七种优先级大家可以参考我下面提供的MessagePriority枚举源代码定义。
      那么在发送消息的时候怎么指定消息的优先级呢?在Message对象里封装有一个属性Priority,接受一个枚举MessagePriority类型的值来设置消息传输的优先级。如下:
1System.Messaging.Message message = new System.Messaging.Message();
2message.Priority = MessagePriority.Highest;  //最高消息优先级

      下面来看看一个在消息传输中使用优先级的示例程序,通过示例程序会学习得更明白。示例程序界面:
      

      根据界面可知,提供了消息名字,消息优先级和消息内容三个输入项,前面曾经说过,这里为了方便演示就仅用了HighestNormal两种类型,当点击发送消息的时候就通过是否选择优先级来设置消息的优先级,代码如下:
 1private void btnSend_Click(object sender, EventArgs e)
 2{
 3    //连接到本地的专用队列myQueue
 4    MessageQueue myQueue = new MessageQueue(".\\private$\\myQueue");
 5    System.Messaging.Message message = new System.Messaging.Message();
 6    message.Label = tbName.Text;
 7    message.Body = tbContext.Text;
 8
 9    if (cbPriority.Checked)
10    {
11        message.Priority = MessagePriority.Highest;
12    }

13    else
14    {
15        message.Priority = MessagePriority.Normal;
16    }

17    myQueue.Send(message);
18    MessageBox.Show("成功发送消息到队列");
19}
     这里我们可以向队列里发送两条消息,以便后面测试读取方法,发送两条消息到队列,此时,从队列消息中可以看到:
           
     "刷新队列"实质上就是把队列里的消息全部读取出来,具体的实现在《ASP.NET中进行消息处理(MSMQ)一》里已经作了详细的介绍,这里就不在多说,看看下面的代码:
 1private void DisplayMessage()
 2        {
 3            //连接到本地队列
 4            MessageQueue myQueue = new MessageQueue(".\\private$\\myQueue");
 5            myQueue.MessageReadPropertyFilter.Priority = true;
 6            DataTable messageTable = new DataTable();
 7            messageTable.Columns.Add("名字");
 8            messageTable.Columns.Add("消息内容");
 9            messageTable.Columns.Add("优先级");
10            XmlMessageFormatter formatter = new XmlMessageFormatter(new string[] "System.String" });
11            try
12            {
13                //从队列中接收消息
14                System.Messaging.Message[] messages = myQueue.GetAllMessages();
15                for (int index = 0; index < messages.Length; index++)
16                {
17                    messages[index].Formatter = formatter;
18
19                    string label = messages[index].Label;
20                    string body = messages[index].Body.ToString();
21                    string priority = messages[index].Priority.ToString();
22
23                    messageTable.Rows.Add(new string[] { label, body, priority });
24                }

25                this.dgvMessage.DataSource = messageTable;
26            }

27            catch (MessageQueueException e1)
28            {
29                MessageBox.Show(e1.Message);
30            }

31        }

32    }
      这里封装了一方法,专门负责从队列里读取全部消息并绑定在DataGridView控件上,这里我们只需要在按扭Click事件里调用这方法就OK。
1private void btnRec_Click(object sender, EventArgs e)
2{
3    DisplayMessage();
4}
     这就完成了给消息设置优先级的消息传输的应用,最终的测试结果如下:
      

注:要完成以上应用还需注意一点,由于消息的优先级是枚举类型,在直接messages[index].Priority.ToString();这种方式来获取优先级转化到字符串的时候,他需要一个过滤器(Filter),否则会抛出一个InvalidCastExceptionle类型的异常,异常信息"接收消息时未检索到属性 Priority。请确保正确设置了 PropertyFilter。",要解决这问题只需要把消息对象的MessageReadPropertyFilter(过滤器) 的Priority设置为true就OK了。见上面代码里!^.^

MessagePriority枚举源代码定义详细如下:
 1// 摘要:
 2//     指定消息队列在消息传递到队列的过程中应用于该消息的优先级,以及指定何时将消息插入目标队列。
 3public enum MessagePriority
 4{
 5    // 摘要:
 6    //     最低消息优先级。
 7    Lowest = 0,
 8    //
 9    // 摘要:
10    //     位于 Low 和 Lowest 消息优先级之间。
11    VeryLow = 1,
12    //
13    // 摘要:
14    //     低消息优先级。
15    Low = 2,
16    //
17    // 摘要:
18    //     普通消息优先级。
19    Normal = 3,
20    //
21    // 摘要:
22    //     位于 System.Messaging.MessagePriority.High 和 System.Messaging.MessagePriority.Normal
23    //     消息优先级之间。
24    AboveNormal = 4,
25    //
26    // 摘要:
27    //     高消息优先级。
28    High = 5,
29    //
30    // 摘要:
31    //     位于 Highest 和 High 消息优先级之间。
32    VeryHigh = 6,
33    //
34    // 摘要:
35    //     最高消息优先级。
36    Highest = 7,
37}

二、事务性消息处理
      事务我想大家对这个词应该都不会陌生,在操作数据库的时候经常都会用到事务,确保操作成功,要么全部完成(成功),要么全部不完成(失败)。在MSMQ中利用事务性处理,可以确保事务中的消息按照顺序传送,只传送一次,并且从目的队列成功地被检索。
     那么,在MSMQ上使用事务性处理怎么实现呢?可以通过创建MessageQueueTransation类的实例并将其关联到MessageQueue组件的实例来执行,执行事务的Begin方法,并将其实例传递到收发方法。然后,调用Commit以将事务的更改保存到目的队列。
     创建事务性消息和普通的消息有一点小小的区别,大家可从下图上体会到:
                                 
     通过代码方式建立事务性消息队列只在Create方法的参数上动动手脚就OK,详细如下:
1//创建普通的专用消息队列
2MessageQueue myMessage = MessageQueue.Create(@".\private$\myQueue");
3//创建事务性的专用消息队列
4MessageQueue myTranMessage =MessageQueue.Create(@".\private$\myQueueTrans"true);

      启动了事务,那么在发送和接收消息的时候肯定是与原来有一定的差别的,这里我就不做详细介绍,下面给出示意性代码,有兴趣的朋友可以直接下载本文示例程序代码了解更多。

普通的消息发送示意性代码:
1//连接到本地的队列
2MessageQueue myQueue = new MessageQueue(".\\private$\\myQueue");
3Message myMessage = new Message();
4myMessage.Body = "消息内容";
5myMessage.Formatter = new XmlMessageFormatter(new Type[] typeof(string) });
6//发送消息到队列中
7myQueue.Send(myMessage);
启动了事务后的消息发送示意性代码:
 1//连接到本地的队列
 2MessageQueue myQueue = new MessageQueue(".\\private$\\myQueueTrans");
 3
 4Message myMessage = new Message();
 5myMessage.Body = "消息内容";
 6myMessage.Formatter = new XmlMessageFormatter(new Type[] typeof(string) });
 7
 8MessageQueueTransaction myTransaction = new MessageQueueTransaction();
 9//启动事务
10myTransaction.Begin();
11//发送消息到队列中
12myQueue.Send(myMessage, myTransaction);  //加了事务
13//提交事务
14myTransaction.Commit();
15Console.WriteLine("消息发送成功!");

读取消息示意性代码:
 1//连接到本地队列
 2MessageQueue myQueue = new MessageQueue(".\\private$\\myQueueTrans");
 3myQueue.Formatter = new XmlMessageFormatter(new Type[] typeof(string) });
 4if (myQueue.Transactional)
 5{
 6    MessageQueueTransaction myTransaction = new MessageQueueTransaction();
 7    //启动事务
 8    myTransaction.Begin();
 9    //从队列中接收消息
10    Message myMessage = myQueue.Receive(myTransaction);
11    string context = myMessage.Body as string//获取消息的内容
12    myTransaction.Commit();
13    Console.WriteLine("消息内容为:" + context);
14}

三、异步消息处理
      在MSMQ中对消息的操作分有同步化操作和异步化操作两种,那两者到底有何区别呢?简单的说同步化操作就是一项操作没有完成前它将堵塞整个进程直到操作完成,下一项操作才会执行。所谓异步化操作则相反,不会堵塞启动操作的调用线程。如果你想在检索消息但不想堵塞其他程序的执行,则可使用异步消息处理。
     在MSMQ中异步接收消息使用BeginReceive方法和EndReceive方法来标记操作的开始和结束,异步查看消息则使用BeginPeek和EndPeek两个方法来标记异步读取的开始和结束。同时,异步接收和查看消息还可以指定超时时间,关于这点我在后续文章里再做详细的介绍,有兴趣的朋友可以关注。
      这里我将使用《ASP.NET中进行消息处理(MSMQ)一》一文里使用过的Book类来作为消息传输,没阅读过的朋友请先阅读这篇文章,了解Book类的结构。下面提供了一个示例,创建队列和发送消息到队列在前面我们已经使用多次了这里就不贴代码了,发送消息这里与第一篇文章中介绍如何发送一个复杂的类型信息到队列比,只是多了事务处理,详细如下:
 1/**//// <summary>
 2/// 发送消息到队列
 3/// </summary>

 4private static void SendMessage()
 5{
 6    MessageQueue myQueue = new MessageQueue(".\\private$\\myAsyncQueue");
 7    if (myQueue.Transactional)
 8    {
 9        Book book = new Book();
10        book.BookId = 1001;
11        book.BookName = "ASP.NET";
12        book.BookAuthor = "ZhangSan";
13        book.BookPrice = 88.88;
14        Message message = new Message(book);
15        message.Formatter = new XmlMessageFormatter(new Type[] typeof(MSMQ.Async.Book) });
16
17        MessageQueueTransaction myTransaction = new MessageQueueTransaction();
18        myTransaction.Begin();
19        myQueue.Send(message, myTransaction);
20        myTransaction.Commit();
21        Console.WriteLine("消息成功发送到队列!");
22    }

23}

异步接收消息:
 1/**//// <summary>
 2/// 异步接收消息
 3/// </summary>

 4private static void AsyncReceiveMessage()
 5{
 6    MessageQueue myQueue = new MessageQueue(".\\private$\\myAsyncQueue");
 7    if (myQueue.Transactional)
 8    {
 9        MessageQueueTransaction myTransaction = new MessageQueueTransaction();
10        //这里使用了委托,当接收消息完成的时候就执行MyReceiveCompleted方法
11        myQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(MyReceiveCompleted);
12        myQueue.Formatter = new XmlMessageFormatter(new Type[] typeof(MSMQ.Async.Book) });
13        myTransaction.Begin();
14        myQueue.BeginReceive();//启动一个没有超时时限的异步操作
15        signal.WaitOne();
16        myTransaction.Commit();
17    }

18}

 1private static void MyReceiveCompleted(Object source, ReceiveCompletedEventArgs asyncResult)
 2{
 3    try
 4    {
 5        MessageQueue myQueue = (MessageQueue)source;
 6        //完成指定的异步接收操作
 7        Message message = myQueue.EndReceive(asyncResult.AsyncResult);
 8        signal.Set();
 9        Book book = message.Body as Book;
10        Console.WriteLine("图书编号:{0}--图书名称:{1}--图书作者:{2}--图书定价:{3}",
11            book.BookId.ToString(),
12            book.BookName,
13            book.BookAuthor,
14            book.BookPrice.ToString());
15        myQueue.BeginReceive();
16    }

17    catch (MessageQueueException me)
18    {
19        Console.WriteLine("异步接收出错,原因:" + me.Message);
20
21    }

22}

四、MSMQ在邮件发送程序中的应用
     在邮件程序的应用中,实现发送邮件的方法有很多种,很多朋友都比较喜欢邮件发送组件(如:JMail),在.NET Framework里也给我们提供了发送邮件的类StmpClient,位于System.Net下。我想很多朋友都曾用到过此类,如果说是在一个小型的邮件应用里,完全没有使用MSMQ的必要,因为数据量不大,直接处理就OK,这里我以邮件程序来说只是出于对MSMQ应用的介绍。说实在的,我也不知道怎么才能把这个东东给介绍清楚,先看看一张图吧!
                        
      现在的需求是这样的,有一个邮件发送客户端(SendMail.aspx,界面效果如上图所示)和一个邮件发送管理的服务端(MailServer.aspx),当在SendMail.aspx里发送邮件的时候,我们不直接将其发到目标地址去,而是将其发送到消息队列,然后由MailServer.aspx来负责从消息队列里读取出邮件信息在将其发送到目标地址。其实SendMail.aspx的职责就是完成把邮件信息发送到消息队列,示意性代码如下:
 1protected void btnSendMail_Click(object sender, EventArgs e)
 2{
 3    //取出数据存入MailInfo对象
 4    MailInfo info = new MailInfo();
 5    info.Title = tbTitle.Text;
 6    info.Content = tbContent.Text;
 7    info.StmpServer = tbSmtpServer.Text;
 8    info.Sender = tbSender.Text;
 9    info.SenderPwd = tbSenderPwd.Text;
10    info.ReceiveAddress = tbReceive.Text;
11
12    if (info != null)
13    {
14        CreateQueue();
15        SendMessage(info);
16    }

17}
     CreateQueue和SendMessage这两个方法完成消息队列的创建和发送信息到队列,MailInfo类封装的是邮件的详细信息(既邮件的属性),详细定义如下: 
封装了邮件的属性
 1public class MailInfo
 2{
 3    public MailInfo()
 4    {
 5       
 6    }

 7
 8    private string _Title;
 9    public string Title
10    {
11        get return _Title; }
12        set { _Title = value; }
13    }

14
15    private string _Content;
16
17    public string Content
18    {
19        get return _Content; }
20        set { _Content = value; }
21    }

22    private string _Sender;
23
24    public string Sender
25    {
26        get return _Sender; }
27        set { _Sender = value; }
28    }

29    private string _SenderPwd;
30
31    public string SenderPwd
32    {
33        get return _SenderPwd; }
34        set { _SenderPwd = value; }
35    }

36    private string _StmpServer;
37
38    public string StmpServer
39    {
40        get return _StmpServer; }
41        set { _StmpServer = value; }
42    }

43    private string _ReceiveAddress;
44
45    public string ReceiveAddress
46    {
47        get return _ReceiveAddress; }
48        set { _ReceiveAddress = value; }
49    }

50}

      转到邮件管理端(MailServer.aspx),他负责从消息队列里读取出邮件信息并把此邮件发送到目标地址去。其实现很简单,说直接点他也就是完成了两项操作(从队列读消息、将消息发送到目的邮箱),从队列读取消息的代码如下:
 1/**//// <summary>
 2/// 连接消息队列并从队列中接收消息
 3/// </summary>

 4private MailInfo ReceiveMessage()
 5{
 6    MailInfo info = null;
 7    //连接到本地队列
 8    MessageQueue myQueue = new MessageQueue(".\\private$\\myMailQueue");
 9    myQueue.Formatter = new XmlMessageFormatter(new Type[] typeof(MailInfo) });
10    try
11    {
12        if (myQueue.Transactional)
13        {
14            MessageQueueTransaction myTransaction = new MessageQueueTransaction();
15            //启动事务
16            myTransaction.Begin();
17            //从队列中接收消息
18            Message myMessage = myQueue.Receive(myTransaction);
19            info = myMessage.Body as MailInfo; //获取消息的内容
20            myTransaction.Commit();
21            return info;
22        }

23
24    }

25    catch (MessageQueueException e)
26    {
27        this.tdError.InnerText = e.Message;
28    }

29    return info;
30}

      该方法(ReceiveMessage)返回的是从队列里读取到的邮件信息,本示例中只是做了读一条信息的实现,如果要把队列里的全部信息读出并发送到目的邮箱,可以参考我前面所介绍的相关知识点来实现。得到了邮件的详细信息,我们就可以使用相应的技术将这信息发送到目标邮箱去,本示例中我采用的是.NET Framework里提供的SmtpClient类来完成的邮件发送,关于SmtpClient类的使用网上有相当丰富的资料介绍,这里我就不做详细的说明,核心代码如下:
 1protected void Button2_Click(object sender, EventArgs e)
 2{
 3    if (info != null)
 4    {
 5        SmtpClient client = new SmtpClient();
 6        client.Host = info.StmpServer;
 7        client.UseDefaultCredentials = false;
 8        client.Credentials = new NetworkCredential(info.Sender, info.SenderPwd);
 9        client.DeliveryMethod = SmtpDeliveryMethod.Network;
10
11        MailMessage message = new MailMessage(info.Sender, info.ReceiveAddress);
12        message.Subject = info.Title;
13        message.Body = info.Content;
14        message.BodyEncoding = Encoding.UTF8;
15        message.IsBodyHtml = true;
16
17        try
18        {
19            //发送邮件到目标地址
20            client.Send(message);
21            this.tdSucces.InnerText = "邮件已成功发送到目标地址:" + info.ReceiveAddress;
22        }

23        catch (Exception ex)
24        {
25            this.tdError.InnerText = "发送失败,失败原因:" + ex.Message;
26        }

27    }

28}

运行后的效果图如下:
                         
      本文中的所有示例程序全部通过调试,能力有限,文中所介绍的不是很清楚,详细可直接下载源代码了解。本代码包里也包含有第一篇文章里的全部示例程序代码。
点击连接下载示例程序代码:示例程序代码下载

转载于:https://www.cnblogs.com/gooddasenlin/archive/2011/04/22/2025193.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247501.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GoJs Pictures 官方介绍文档

图片 使用Picture类显示图像。 最常见的用法是使用URL字符串设置Picture.source属性&#xff0c;以及通过GraphObject.desiredSize&#xff08;图对象的所需尺寸&#xff09;获取或通过设置GraphObject.width&#xff08;图对象的宽&#xff09;和GraphObject.height&#xff0…

怎样购买及安装ssl安全证书

查找资料记录&#xff0c;不是我的项目笔记 现在越来越多的网站都开始用安全链接了&#xff0c;在国外的话&#xff0c;如果不是一个安全链接&#xff0c;用户很大程度上会拒绝使用&#xff0c;所有安全链接是未来的趋势&#xff0c;楼主第一次配安全证书的时候&#xff0c;刚刚…

(转载)Git使用教程:最详细、最傻瓜、最浅显、真正手把手教!

转载自 Git使用教程 预警&#xff1a;因为详细&#xff0c;所以行文有些长&#xff0c;新手边看边操作效果出乎你的预料&#xff09;一&#xff1a;Git是什么&#xff1f; Git是目前世界上最先进的分布式版本控制系统。 工作原理 / 流程&#xff1a; Workspace&#xff1a;工作…

soureTree中如何设置git 用户名与密码 SourceTree提交修改用户详细图文方法

mac上软件更新&#xff1a; 现在没有网络小模块了&#xff0c;在同行右边高级里面有默认用户名删除即可&#xff01;&#xff01;&#xff01;&#xff01; sourceTree 切换Git登录用户&#xff0c;之前在SourceTree提交远程服务用的是同事的账号&#xff0c;同事离职后账号也…

box-sizing的使用

box-sizing 人们慢慢的意识到传统的盒子模型不直接&#xff0c;所以他们新增了一个叫做 box-sizing 的CSS属性。当你设置一个元素为 box-sizing: border-box; 时&#xff0c;此元素的内边距和边框不再会增加它的宽度。这里有一个与前一页相同的例子&#xff0c;唯一的区别是两…

更新node最新版本方法和 npm install -g n 运行错误

使用xshell连接linux服务器后&#xff0c;首先输入node -v查看当前使用的版本 如果上面查看的版本比较低&#xff0c;则可以开始升级 清除npm cache 升级之前还需要安装n模块&#xff0c;n模块是专门用来管理nodejs的版本 输入npm install -g n n模块安装完成之后&#x…

Atom React或前端插件推荐

分享一些Atom个人在用的插件,喜欢请点赞 1. color-picker 取色工具 2. pigments 编辑器中直接查看代码所代表的颜色&#xff0c;工具虽小但是很实用。 3. minimap 仿sublime text的缩略代码查看&#xff0c;想找的地方一目了然。 4. highlight-selected 选择某段代码自动高…

Tapable.plugin is deprecated. Use new API on `.hooks` instead

问题描述 在使用extract-text-webpack-plugin给webpack打包时出现报错 Tapable.plugin is deprecated. Use new API on .hooks instead 1 问题原因 extract-text-webpack-plugin目前版本不支持webpack4。 解决方案 使用extract-text-webpack-plugin的最新的beta版 npm inst…

多重表(广义表)

在深入浅出数据结构系列前面的文章中&#xff0c;我们一直在讨论“线性表”&#xff0c;其形式如下&#xff1a; 由a1,a2,a3,……a(n-1)个元素组成的序列&#xff0c;其中每一个元素ai(0<i<n)都是一个“原子”&#xff0c;“原子”的意思就是说元素本身是一个个体&#x…

简单教你React父子组件间平级组件间传值

国庆充电特辑&#xff1a; 堵车堵死&#xff0c;废话不多说直接上菜。 1.父组件对子组件传值 利用props属性传值 class Component extends React.Component {constructor (props) {super(props);}render() {return (<div><h1>I am {this.props.name}</h1>…

Requests库的主要方法:requests.request为requests.get和requests.post两个的汇总,只是需要传方法...

1. requests.request(method,url,**kwargs&#xff09; method&#xff1a;请求方式&#xff0c;对应get/put/post等七种&#xff1a;拟获取页面的url链接&#xff1a;控制访问参数&#xff0c;共13个method&#xff1a;请求方式rrequests.request(GET,url,**kwargs) r reques…

jQuery插件开发教程

jQuery插件开发精品教程&#xff0c;让你的jQuery提升一个台阶 要说jQuery 最成功的地方&#xff0c;我认为是它的可扩展性吸引了众多开发者为其开发插件&#xff0c;从而建立起了一个生态系统。这好比大公司们争相做平台一样&#xff0c;得平台者得天下。苹果&#xff0c;微软…

微服务深入浅出(7)-- 网关路由Zuul

Zuul用于构建边界服务&#xff0c;致力于动态路由&#xff0c;过滤&#xff0c;监控&#xff0c;弹性伸缩和安全等方向。 1、ZuulRibbonEureka结合&#xff0c;可以实现智能路由和负载均衡 2、网关将所有服务的API接口统一聚合统一暴露 3、网关统一爆率接口后&#xff0c;可以做…

C# webkit内核 网页填表

比如我要操作的是下面的input 用到的方法是 调用如下&#xff1a; webkit.StringByEvaluatingJavaScriptFromString("document.getElementsByClassName(login_i_con_li_ipt name)[0].valueThis is a Demo."); 类似这种div在webkit中好像是无法通过常规方法模拟的 这时…

p字间距 html段落内文字设置字间距间隔

只对段落p内文字设置字间距&#xff0c;段落<p>是html段落标签&#xff0c;以<p>开始&#xff0c;以</p>结束&#xff0c;通常文章分段使用p标签&#xff0c;而有时小局部布局也可以使用p来布局。通过css设置其样式实现排版目的。 这里针对p设置字间距&…

基本数据类型

上节回顾 1.循环打印数列1&#xff0c;3&#xff0c;5&#xff0c;.........&#xff0c;99 for i in range(100):if i%21:print (i) 2.turtle 库 # penup 抬笔 # pendown 落笔 # pensize 画笔大小 # pencolor 画笔颜色## 画笔运动函数 # fd 前进 # bk 后退 # goto 到达指定的坐…

修改系统默认 alert 弹框样式

修改默认 alert 弹框&#xff0c;思路很简单&#xff0c;定义一个 alert(e) 函数&#xff0c;加载最开头即可。 css部分&#xff1a; <style>#msg{width:266px;position: fixed;z-index:999;top: 49%;margin-top:-80px;left:50%;margin-left:-133px;background:#fff;bo…

:nth-child(n)与:nth-of-type(n)为啥显示不对呢

首先是二者的区别 :nth-child(n) 是选择父元素的第n个子元素。 :nth-of-type(n) 是选择父元素的第n个同类型的子元素 举个例子&#xff1a; <div class"read"><h1>title</h1><p>paragraph1</p><p>paragraph2</p> <!…

css3 box-shadow阴影(内外阴影与发光)讲解

基础说明&#xff1a; 外阴影&#xff1a;box-shadow: X轴 Y轴 Rpx color; 属性说明&#xff08;顺序依次对应&#xff09;&#xff1a; 阴影的X轴(可以使用负值) 阴影的Y轴(可以使用负值) 阴影模糊值&#xff08;大小&#xff09; 阴影的颜色 内阴影&#xff1a;b…

远程链接错误:这可能是由于credssp加密oracle修正

此错误解决办法 1.WinR 输入regedit打开注册表 找到对应的以下目录HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System 此时如果System下没有CredSSP时创建CredSSP没有Parameters时,创建Parameters 创建方法:右建>>新建>>项 2.在Para…