FBV即以函数的形式实现视图函数,CBV即以类的形式实现视图函数;相比而言,CBV根据请求方式书写各自的代码逻辑,结构清晰明了,但是由于多了一层反射机制,性能要差一些;FBV执行效率要高一些,但是代码逻辑看起来要混乱一些。

一、CBV源码实现

  django支持以类的形式写视图函数,它需要继承自django.views.generic.base.View。可以通过from django.views.gener

  1. class View:
  2. """
  3. Intentionally simple parent class for all views. Only implements
  4. dispatch-by-method and simple sanity checking.
  5. """
  6.   # 1.允许可被重写的方法列表
  7. http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
  8.  
  9. def __init__(self, **kwargs):
  10. """
  11. Constructor. Called in the URLconf; can contain helpful extra
  12. keyword arguments, and other things.
  13. """
  14. # Go through keyword arguments, and either save their values to our
  15. # instance, or raise an error.
  16. for key, value in kwargs.items():
  17. setattr(self, key, value)
  18.   # 2.在path路径中将views.funciton改写为views.Class.as_view(),其实是执行了这个函数;initkwaegs可以写入传递的请求方式;
      """
        在views.Class.as_view()时,首先把cls,也就是自己传递给了这个函数;
        定义了view函数后,给view函数设置view_class和view_initkwargs属性;
        将view函数作为装饰器,装饰给这个cls,以及cls中的dispatch方法;其本质上就是将initkwarga传递进去;
        真正返回的是view函数,它内部实例化了当前的cls类,可以使用cls中的方法;
        整个过程相当于调用了View.view方法,只不过对这个方法做了一下包裹.
        感觉像是一个人模型(Class)在空间戒指(as_view)隐藏了自身的属性(view_class和view_initkwargs)和功能(view)。
      """

  19. @classonlymethod
  20. def as_view(cls, **initkwargs):
  21. """Main entry point for a request-response process."""
  22. for key in initkwargs:
  23. if key in cls.http_method_names:
  24. raise TypeError("You tried to pass in the %s method name as a "
  25. "keyword argument to %s(). Don't do that."
  26. % (key, cls.__name__))
  27. if not hasattr(cls, key):
  28. raise TypeError("%s() received an invalid keyword %r. as_view "
  29. "only accepts arguments that are already "
  30. "attributes of the class." % (cls.__name__, key))
         # 3.path调用views.Class.as_view(),也就是执行view函数;view函数实例化了一个当前Class的对象,并把request以及参数封装传递给了Class.dispatch,然后调用Class.dispatchdef view(request, *args, **kwargs):
  31. self = cls(**initkwargs)
  32. if hasattr(self, 'get') and not hasattr(self, 'head'):
  33. self.head = self.get
  34. self.request = request
  35. self.args = args
  36. self.kwargs = kwargs
  37. return self.dispatch(request, *args, **kwargs)
  38. view.view_class = cls
  39. view.view_initkwargs = initkwargs
  40.  
  41. # take name and docstring from class
  42. update_wrapper(view, cls, updated=())
  43.  
  44. # and possible attributes set by decorators
  45. # like csrf_exempt from dispatch
  46. update_wrapper(view, cls.dispatch, assigned=())
  47. return view
  48.   # 4.dispatch负责在FBV类中反射相应的方法
      """
      它从request.method中获取请求类型(假设是GET),并进行反射,并交给我们在Class中写好的对应方法(GET)去执行
      那么dispatch就相当于一个请求分发器,它在请求处理前执行
      """
      
    def dispatch(self, request, *args, **kwargs):
  49. # Try to dispatch to the right method; if a method doesn't exist,
  50. # defer to the error handler. Also defer to the error handler if the
  51. # request method isn't on the approved list.
  52. if request.method.lower() in self.http_method_names:
  53. # 如果请求方法在self.http_method_not_allowed,就反射相应的方法
  54. handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
  55. else:
  56. # 否则就调用self.http_method_not_allowed
  57. handler = self.http_method_not_allowed
  58. return handler(request, *args, **kwargs) # 执行该方法
  59.  
  60. def http_method_not_allowed(self, request, *args, **kwargs):
  61. logger.warning(
  62. 'Method Not Allowed (%s): %s', request.method, request.path,
  63. extra={'status_code': 405, 'request': request}
  64. )
  65. return HttpResponseNotAllowed(self._allowed_methods())
  66.  
  67. def options(self, request, *args, **kwargs):
  68. """Handle responding to requests for the OPTIONS HTTP verb."""
  69. response = HttpResponse()
  70. response['Allow'] = ', '.join(self._allowed_methods())
  71. response['Content-Length'] = ''
  72. return response
  73.  
  74. def _allowed_methods(self):
  75. return [m.upper() for m in self.http_method_names if hasattr(self, m)]
  1. from functools import update_wrapper
  2. class Person:
  3. def __init__(self, **kwargs):
  4. pass
  5.  
  6. @classmethod
  7. def as_View(cls, **initkwargs):
  8. def view(request, *args, **kwargs):
  9. self = cls(**initkwargs)
  10. self.request = request
  11. self.args = args
  12. self.kwargs = kwargs
  13. return self.dispatch(request, *args, **kwargs)
  14.  
  15. view.view_class = cls
  16. view.view_initkwargs = initkwargs
  17. update_wrapper(view, cls, updated=())
  18. update_wrapper(view, cls.dispatch, assigned=())
  19.  
  20. return view
  21.  
  22. def dispatch(self, request, *args, **kwargs):
  23. print(request)
  24. print(*args)
  25. print(kwargs)
  26. return "HttpHandler"
  27.  
  28. if __name__ == '__main__':
  29. view = Person.as_View(**{"name": "Jan", "age":100})
  30. print(view)
  31. print(view.view_class)
  32. print(view.view_initkwargs)
  33. view("request", 1234, gender="female")
  34. print()
  35.  
  36. """
  37. <function Person at 0x10c75b840>
  38. <class '__main__.Person'>
  39. {'name': 'Jan', 'age': 100}
  40. request
  41. 1234
  42. {'gender': 'female'}
  43. """

as_view的逻辑

二、使用CBV

  对比FBV:

  1. # views.py
    from django.shortcuts import render, redirect
  2. from django.views.generic.base import View
  3.  
  4. # CBV写法
  5. class Login(View):
  6. def get(self, request, *args, **kwargs):
  7. return render(request, 'app04/login.html', {"msg": ''})
  8.  
  9. def post(self, request, *args, **kwargs):
  10. user= request.POST.get("user", False)
  11. pwd = request.POST.get("pwd", False)
  12. if user == "root" and pwd == "root":
  13. request.session["username"] = user
  14. return redirect("index")
  15. else:
  16. msg = "用户名或密码错误"
  17. return render(request, 'app04/login.html', {"msg": ''})
  18.  
  19. # FBV写法
  20. def login(request):
  21. msg = ""
  22. # print(request.environ["Set-Cookie"])
  23. if request.method == "POST":
  24. user= request.POST.get("user", False)
  25. pwd = request.POST.get("pwd", False)
  26. if user == "root" and pwd == "root":
  27. request.session["username"] = user
  28. return redirect("index")
  29. else:
  30. msg = "用户名或密码错误"
  31. return render(request, 'app04/login.html', {"msg": msg})
  32.  
  33. def index(request):
  34. username = request.session.get("username")
  35. if username:
  36. return render(request, 'app04/index.html', {'username': username})
  37.  
  38. return redirect('login')
  1. # urls.py
  2. from django.urls import path
  3. from app04 import views
  4.  
  5. urlpatterns = [
  6. # path('login', views.login, name="login"),
  7. path('index', views.index, name="index"),
  8. path('login', views.Login.as_view(), name="login")
  9. ]

三、CBV使用

  django.utils.decorators.py是django内置的装饰器包,提供了对类、方法以及中间件的装饰功能。

  1. "Functions that help with dynamically creating decorators for views."
  2.  
  3. # For backwards compatibility in Django 2.0.
  4. from contextlib import ContextDecorator # noqa
  5. from functools import WRAPPER_ASSIGNMENTS, update_wrapper, wraps
  6.  
  7. class classonlymethod(classmethod):
  8. def __get__(self, instance, cls=None):
  9. if instance is not None:
  10. raise AttributeError("This method is available only on the class, not on instances.")
  11. return super().__get__(instance, cls)
  12.  
  13. def method_decorator(decorator, name=''):
  14. """
  15. Convert a function decorator into a method decorator
  16. """
  17. # 'obj' can be a class or a function. If 'obj' is a function at the time it
  18. # is passed to _dec, it will eventually be a method of the class it is
  19. # defined on. If 'obj' is a class, the 'name' is required to be the name
  20. # of the method that will be decorated.
  21. def _dec(obj):
  22. is_class = isinstance(obj, type)
  23. if is_class:
  24. if name and hasattr(obj, name):
  25. func = getattr(obj, name)
  26. if not callable(func):
  27. raise TypeError(
  28. "Cannot decorate '{0}' as it isn't a callable "
  29. "attribute of {1} ({2})".format(name, obj, func)
  30. )
  31. else:
  32. raise ValueError(
  33. "The keyword argument `name` must be the name of a method "
  34. "of the decorated class: {0}. Got '{1}' instead".format(
  35. obj, name,
  36. )
  37. )
  38. else:
  39. func = obj
  40.  
  41. def decorate(function):
  42. """
  43. Apply a list/tuple of decorators if decorator is one. Decorator
  44. functions are applied so that the call order is the same as the
  45. order in which they appear in the iterable.
  46. """
  47. if hasattr(decorator, '__iter__'):
  48. for dec in decorator[::-1]:
  49. function = dec(function)
  50. return function
  51. return decorator(function)
  52.  
  53. def _wrapper(self, *args, **kwargs):
  54. @decorate
  55. def bound_func(*args2, **kwargs2):
  56. return func.__get__(self, type(self))(*args2, **kwargs2)
  57. # bound_func has the signature that 'decorator' expects i.e. no
  58. # 'self' argument, but it is a closure over self so it can call
  59. # 'func' correctly.
  60. return bound_func(*args, **kwargs)
  61. # In case 'decorator' adds attributes to the function it decorates, we
  62. # want to copy those. We don't have access to bound_func in this scope,
  63. # but we can cheat by using it on a dummy function.
  64.  
  65. @decorate
  66. def dummy(*args, **kwargs):
  67. pass
  68. update_wrapper(_wrapper, dummy)
  69. # Need to preserve any existing attributes of 'func', including the name.
  70. update_wrapper(_wrapper, func)
  71.  
  72. if is_class:
  73. setattr(obj, name, _wrapper)
  74. return obj
  75.  
  76. return _wrapper
  77. # Don't worry about making _dec look similar to a list/tuple as it's rather
  78. # meaningless.
  79. if not hasattr(decorator, '__iter__'):
  80. update_wrapper(_dec, decorator)
  81. # Change the name to aid debugging.
  82. if hasattr(decorator, '__name__'):
  83. _dec.__name__ = 'method_decorator(%s)' % decorator.__name__
  84. else:
  85. _dec.__name__ = 'method_decorator(%s)' % decorator.__class__.__name__
  86. return _dec
  87.  
  88. def decorator_from_middleware_with_args(middleware_class):
  89. """
  90. Like decorator_from_middleware, but return a function
  91. that accepts the arguments to be passed to the middleware_class.
  92. Use like::
  93.  
  94. cache_page = decorator_from_middleware_with_args(CacheMiddleware)
  95. # ...
  96.  
  97. @cache_page(3600)
  98. def my_view(request):
  99. # ...
  100. """
  101. return make_middleware_decorator(middleware_class)
  102.  
  103. def decorator_from_middleware(middleware_class):
  104. """
  105. Given a middleware class (not an instance), return a view decorator. This
  106. lets you use middleware functionality on a per-view basis. The middleware
  107. is created with no params passed.
  108. """
  109. return make_middleware_decorator(middleware_class)()
  110.  
  111. # Unused, for backwards compatibility in Django 2.0.
  112. def available_attrs(fn):
  113. """
  114. Return the list of functools-wrappable attributes on a callable.
  115. This was required as a workaround for http://bugs.python.org/issue3445
  116. under Python 2.
  117. """
  118. return WRAPPER_ASSIGNMENTS
  119.  
  120. def make_middleware_decorator(middleware_class):
  121. def _make_decorator(*m_args, **m_kwargs):
  122. middleware = middleware_class(*m_args, **m_kwargs)
  123.  
  124. def _decorator(view_func):
  125. @wraps(view_func)
  126. def _wrapped_view(request, *args, **kwargs):
  127. if hasattr(middleware, 'process_request'):
  128. result = middleware.process_request(request)
  129. if result is not None:
  130. return result
  131. if hasattr(middleware, 'process_view'):
  132. result = middleware.process_view(request, view_func, args, kwargs)
  133. if result is not None:
  134. return result
  135. try:
  136. response = view_func(request, *args, **kwargs)
  137. except Exception as e:
  138. if hasattr(middleware, 'process_exception'):
  139. result = middleware.process_exception(request, e)
  140. if result is not None:
  141. return result
  142. raise
  143. if hasattr(response, 'render') and callable(response.render):
  144. if hasattr(middleware, 'process_template_response'):
  145. response = middleware.process_template_response(request, response)
  146. # Defer running of process_response until after the template
  147. # has been rendered:
  148. if hasattr(middleware, 'process_response'):
  149. def callback(response):
  150. return middleware.process_response(request, response)
  151. response.add_post_render_callback(callback)
  152. else:
  153. if hasattr(middleware, 'process_response'):
  154. return middleware.process_response(request, response)
  155. return response
  156. return _wrapped_view
  157. return _decorator
  158. return _make_decorator
  159.  
  160. class classproperty:
  161. def __init__(self, method=None):
  162. self.fget = method
  163.  
  164. def __get__(self, instance, cls=None):
  165. return self.fget(cls)
  166.  
  167. def getter(self, method):
  168. self.fget = method
  169. return self

装饰器

  请求处理装饰:

  1. from django.shortcuts import render, redirect
  2. from django.views.generic.base import View
  3. from django.utils.decorators import method_decorator
  4.  
  5. def host(func):
  6. def fn(request, *args, **kwargs):
  7. print(request.get_host())
  8. return func(request, *args, **kwargs)
  9. return fn
  10. def get(func):
  11. def fn(request, *args, **kwargs):
  12. print(request.method)
  13. return func(request, *args, **kwargs)
  14. return fn
  15.  
  16. class Login(View):
  17. @method_decorator(host) # 给dispatch添加装饰器,所有请求方式都执行
  18. def dispatch(self, request, *args, **kwargs):
  19. return super().dispatch(request, *args, **kwargs) # dispatch反射,一定要return
  20.  
  21. @method_decorator(get) # 给单个请求添加装饰器
  22. def get(self, request, *args, **kwargs):
  23. return render(request, 'app04/login.html', {"msg": ''})
  24.  
  25. def post(self, request, *args, **kwargs):
  26. user= request.POST.get("user", False)
  27. pwd = request.POST.get("pwd", False)
  28. if user == "root" and pwd == "root":
  29. request.session["username"] = user
  30. return redirect("index")
  31. else:
  32. msg = "用户名或密码错误"
  33. return render(request, 'app04/login.html', {"msg": ''})

  上面可以重写,把装饰器写在类上,并指定给要装饰的函数

  1. from django.shortcuts import render, redirect
  2. from django.views.generic.base import View
  3. from django.utils.decorators import method_decorator
  4.  
  5. def host(func):
  6. def fn(request, *args, **kwargs):
  7. print(request.get_host())
  8. return func(request, *args, **kwargs)
  9. return fn
  10. def get(func):
  11. def fn(request, *args, **kwargs):
  12. print(request.method)
  13. return func(request, *args, **kwargs)
  14. return fn
  15.  
  16. @method_decorator(get, name="get") # 给单个请求添加装饰器
  17. @method_decorator(host, name="dispatch") # 给dispatch添加装饰器,所有请求方式都执行;一定要通过name指定要装饰的函数
  18. class Login(View):
  19.  
  20. def dispatch(self, request, *args, **kwargs):
  21. return super().dispatch(request, *args, **kwargs) # dispatch反射,一定要return
  22. def get(self, request, *args, **kwargs):
  23. return render(request, 'app04/login.html', {"msg": ''})
  24. def post(self, request, *args, **kwargs):
  25. user= request.POST.get("user", False)
  26. pwd = request.POST.get("pwd", False)
  27. if user == "root" and pwd == "root":
  28. request.session["username"] = user
  29. return redirect("index")
  30. else:
  31. msg = "用户名或密码错误"
  32. return render(request, 'app04/login.html', {"msg": ''})

四、view类及其子类

  view相关类在django.views.generic文件下。它通过__all__指明了所有可以调用的视图函数及其子类。其中的"View"位于.base.py文件里,是其它类的基类,它的相关内容已经在上文做了标注。其它子类用于辅助快速构建视图函数。

  1. # django.views.generic.__init__.py
  2. from django.views.generic.base import RedirectView, TemplateView, View
  3. from django.views.generic.dates import (
  4. ArchiveIndexView, DateDetailView, DayArchiveView, MonthArchiveView,
  5. TodayArchiveView, WeekArchiveView, YearArchiveView,
  6. )
  7. from django.views.generic.detail import DetailView
  8. from django.views.generic.edit import (
  9. CreateView, DeleteView, FormView, UpdateView,
  10. )
  11. from django.views.generic.list import ListView
  12.  
  13. __all__ = [
  14. 'View', 'TemplateView', 'RedirectView', 'ArchiveIndexView',
  15. 'YearArchiveView', 'MonthArchiveView', 'WeekArchiveView', 'DayArchiveView',
  16. 'TodayArchiveView', 'DateDetailView', 'DetailView', 'FormView',
  17. 'CreateView', 'UpdateView', 'DeleteView', 'ListView', 'GenericViewError',
  18. ]
  19.  
  20. class GenericViewError(Exception):
  21. """A problem in a generic view."""
  22. pass

  1.TemplateView

  用于在get请求时直接返回一个静态模板。源码如下:

  1. class TemplateView(TemplateResponseMixin, ContextMixin, View): # 只支持get
  2. """
  3. Render a template. Pass keyword arguments from the URLconf to the context.
  4. """
  5. def get(self, request, *args, **kwargs):
  6. context = self.get_context_data(**kwargs)
  7. return self.render_to_response(context)

  用例:

  1. # app01/urls.py
  2. from django.urls import path
  3. from django.views.generic import TemplateView
  4. urlpatterns = [
  5. path("example1", TemplateView.as_view(template_name="app01/example1.html")), # 不用在app01/views.py中写视图函数
  6. ]
  7. # templates/app01/example1.html
  8. ...
    <h1>this is a example1</h1>
    ...

  2.ListView

  给静态文件传递queryset列表。源码如下:

  1. class ListView(MultipleObjectTemplateResponseMixin, BaseListView): # 继承了这两个父类
  2. """
  3. Render some list of objects, set by `self.model` or `self.queryset`.
  4. `self.queryset` can actually be any iterable of items, not just a queryset.
  5. """

  用例:

  1. # app01/urls.py
  2. from django.urls import path
  3. from .models import Book
  4. from django.views.generic import *
  5. bookinfo = {
  6. 'queryset': Book.objects.all(), # Book.objects.all去掉括号,会动态地进行查询
  7. 'template_name': "app01/example2.html"
  8. }
  9.  
  10. urlpatterns = [
  11. path("example1", TemplateView.as_view(template_name="app01/example1.html")),
  12. path("example2", ListView.as_view(**bookinfo)),
  13. ]
  14.  
  15. # templates/app01/example2.py
  16. ...
  17. <p>example2</p>
  18. {% for obj in object_list %} # 注意这里的object_list,它是默认的变量名,即对应bookinfo里的queryset.
  19. <p>{{ obj.id }}, {{ obj.name }}</p>
  20. {% endfor %}
  21. ...

  它其实等价于:

  1. # app01/urls.py
  2.  
  3. from django.urls import path
  4. from .views import *
  5. urlpatterns = [
  6. path("example3", BookListView.as_view(),)
  7. ]
  8.  
  9. # app01/views.py
  10. from django.views.generic import ListView
  11. from .models import Book
  12. class BookListView(ListView):
  13. model = Book
  14. queryset = Book.objects.all()
  15. template_name = "app01/example2.html"
  16.  
  17. def get_context_data(self, *, object_list=None, **kwargs):
  18. return super().get_context_data(**kwargs)

django(六):view和cbv的更多相关文章

  1. Django的View(视图)和路由系统

    一.Django的View(视图) 1.介绍 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一 ...

  2. Django的View(视图层)

    目录 Django的View(视图层) 一.JsonResponse 二.后端接收前端的文件 三. FBV和CBV(源码分析) 四.settings.py配置文件源码分析 五. 请求对象(HttpRe ...

  3. django的FBV和CBV

    title: python djano CBV FBV tags: python, djano, CBV, FBV grammar_cjkRuby: true --- python django的fu ...

  4. Django的View(视图)

    Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误, ...

  5. 通过django的rest-framework……(CBV)

    为什么不使用FBV,因为CBV重用性很高 先看一个例子: from django.views.generic.base import View from django.http import Http ...

  6. WEB框架Django之中间件/缓存/CBV/信号

    一Djano的中间件 1 中间件的概念 中间件顾名思义,是介于request与respose处理之间的一道处理过程,相对比较轻量级,并且全局上改变django的输入与输出.因为改变是全局, 所有需要谨 ...

  7. Python学习---django知识补充之CBV

    Django知识补充之CBV Django: url    -->  def函数      FBV[function based view]  用函数和URL进行匹配 url    --> ...

  8. django中介模型,CBV模型,及logging日志配制

    1.中介模型 中介模型,这个是在我们创建表格时,多对多添加的时候应用到的,通过制定ManyToManyField字段中的through参数来定义,为两者的关系新建一个中介class 为什么会产生这个中 ...

  9. day 67 Django的view 与路由

    一.Django中的视图 CBV和FBV 我们之前写过的都是基于函数的view,就叫FBV.还可以把view写成基于类的. url(r'^add_publisher/',views.AddPublis ...

  10. Django 反向解析 request CBV

    正则路径中的分组 无名分组 分组的概念:就是给某一段正则表达式用小括号括起来 无名分组按位置传参数,一一对应. view中除去request,其他形参数量要与urls中分组数量一致. 无名分组就是将括 ...

随机推荐

  1. hdoj1045 Fire Net(二分图最大匹配)

    题意:给出一个图,其中有 . 和 X 两种,. 为通路,X表示墙,在其中放炸弹,然后炸弹不能穿过墙,问你最多在图中可以放多少个炸弹? 这个题建图有点复杂orz. 建图,首先把每一行中的可以放一个炸弹的 ...

  2. vue学前班004(基础指令与使用技巧)

    我学vue 的最终目的是为了 做apicloud 和vue 的开发  作为配合apicloud的前端框架使用 所以项目用不到的会暂时不介绍. (强烈建议  官网案例走一遍) 基础指令的学习(结合aui ...

  3. iOS-CocoaPods安装及使用

    1. 安装 Ruby 对于iOS开发者,CocoaPods是最方便的第三方管理工具了,但是怎么安装CocoaPods呢,安装CocoaPods之前,要确保mac已经安装上Ruby,但在安装Ruby时, ...

  4. 【bzoj4589】Hard Nim FWT+快速幂

    题目大意:给你$n$个不大于$m$的质数,求有多少种方案,使得这$n$个数的异或和为$0$.其中,$n≤10^9,m≤10^5$. 考虑正常地dp,我们用$f[i][j]$表示前$i$个数的异或和为$ ...

  5. 2、如何解决xamarin没有相关教程的的指导贴

    本篇文章主要在于解决xamarin相关文档偏少的问题. 最终的代码并不重要.重要的还是那种处理的方式 授人以渔 群里有群友讨论说需要读取安卓的 充电电流.这样的问题实际上在原生java有一堆.但是到了 ...

  6. 剑指offer三十之连续子数组的最大和

    一.题目 HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学.今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决.但是,如果向量 ...

  7. ActiveMQ学习--001--ActiveMQ和消息中间件

    一.ActiveMQ简介 1,ActiveMQ是什么 ActiveMQ是Apache推出的开源的,完全支持JMS1.1和J2EE 1.4规范的JMS  Provider实现的消息中间件(MOM) 2, ...

  8. 关于注解Annotation第一篇

    注解的定义格式如下: public @interface 注解名 {定义体} 定义体就是方法的集合,每个方法实则是声明了一个配置参数.方法的名称作为配置参数的名称,方法的返回值类型就是配置参数的类型. ...

  9. redis-集群创建脚本

    之前建好了redis集群, 但没有找到集群重启的机制, 停电2次, 重新创建太麻烦, 于是写了个脚本辅助启动 redis的创建过程可以看: http://www.cnblogs.com/wenbron ...

  10. 推荐的bootstrap之 formgroup表单布局样式

    一直没能找到比较好的Form Group样式,直到找到如下样式 转自 https://www.cnblogs.com/jokerjason/p/5721349.html <form class= ...