主要完成:核心分发控制器+Controller和Service注入容器+对象自动装配+控制器方法获取参数+视图解析+返回 JSON格式数据
创建 Maven 项目,File-New-Project-Maven
将 pom.xml 文件中的编译版本改为1.8
在 src 目录下创建以下目录:
java 代码放在 java 目录下,相关的资源文件放在 resource 目录下,对 maven 的 web 项目而言,resource 就是类路径。前端页面放在 webapp 下,该目录对应之前的 web 目录。test/java 目录用于存放测试文件,测试需要的资源文件放在 test/resource 目录下。
在 pom.xml 中引入基本的 jar 包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--引入原生servlet依赖的jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<!--
1.scope表示引入jar包的作用范围,
2.provided表示项目在打包放到生产环境时,不需要打上servlet-api.jar
3.因为 tomcat本身就有该jar包,使用tomcat的即可,防止版本冲突
-->
<scope>provided</scope>
</dependency>
<!--引入dom4j,用于解析xml-->
<dependency>
<groupId>dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>1.6.1</version>
</dependency>
<!--引入常用的工具类jar包,该jar含有很多常用的类-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.5</version>
</dependency>
</dependencies>
说明:编写 MyDispatcherServlet,充当原生的 DispatcherServlet(即核心控制器)
创建 src/main/java/com/li/myspringmvc/servlet/MyDispatcherServlet.java,充当原生的前端控制器。
package com.li.myspringmvc.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 李
* @version 1.0
* 1.MyDispatcherServlet 充当原生的 DispatcherServlet,它的本质就是一个Servlet
* 因此继承 HttpServlet
*/
public class MyDispatcherServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("MyDispatcherServlet doGet() 被调用..");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("MyDispatcherServlet doPost() 被调用..");
}
}
创建 src/main/resources/myspringmvc.xml,充当原生的 applicationContext-mvc.xml(即 spring 容器配置文件)
配置 src/main/webapp/WEB-INF/web.xml
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<servlet>
<servlet-name>MyDispatcherServlet</servlet-name>
<servlet-class>com.li.myspringmvc.servlet.MyDispatcherServlet</servlet-class>
<!--给前端控制器指定配置参数,指定要操作的spring容器文件-->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:myspringmvc.xml</param-value>
</init-param>
<!--要求该对象在tomcat启动时就自动加载-->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>MyDispatcherServlet</servlet-name>
<!--作为前端控制器,拦截所有请求-->
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
配置 Tomcat,进行测试
浏览器访问 http://localhost:8080/li_springmvc/aaa
任务2的总目标是:
实现自己的 @Controller 注解和 @RequestMapping 注解,当浏览器访问指定的 URL 时,由前端控制器,找到 Controller 的某个方法,然后通过 tomcat 将数据返回给浏览器。
步骤一:两个注解和测试Controller
(1)Controller 注解
package com.li.myspringmvc.annotation;
import java.lang.annotation.*;
/**
* @author 李
* @version 1.0
* 该注解用于标识一个控制器组件
* 1.@Target(ElementType.TYPE) 指定自定义注解可修饰的类型
* 2.@Retention(RetentionPolicy.RUNTIME) 作用范围,RUNTIME使得可以通过反射获取自定义注解
* 3.@Documented 在生成文档时,可以看到自定义注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
String value() default "";
}
(2)RequestMapping 注解
package com.li.myspringmvc.annotation;
import java.lang.annotation.*;
/**
* @author 李
* @version 1.0
* RequestMapping 注解用于指定控制器-方法的映射路径
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
String value() default "";
}
(3)用于测试的控制器 MonsterController.java
package com.li.controller;
import com.li.myspringmvc.annotation.Controller;
import com.li.myspringmvc.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author 李
* @version 1.0
*/
@Controller
public class MonsterController {
//编写方法,可以列出妖怪列表
//springmvc支持原生的servlet api,为了看到底层机制,这里直接放入两个参数
@RequestMapping(value = "/monster/list")
public void listMonster(HttpServletRequest request, HttpServletResponse response) {
//设置编码
response.setContentType("text/html;charset=utf-8");
//获取writer,返回提示信息
try {
PrintWriter printWriter = response.getWriter();
printWriter.print("<h1>妖怪列表信息</h1>");
} catch (IOException e) {
e.printStackTrace();
}
}
}
步骤二:配置容器文件 springmvc.xml,指定扫描的包
指定扫描的包是为了之后使用注解获取需要反射的类
如果需要添加新的扫描包,在base-package添加包路径,用逗号表示间隔。
<?xml version="1.0" encoding="utf-8" ?>
<beans>
<!--指定要扫描的包及其子包的java类-->
<component-scan base-package="com.li.controller,com.li.service"/>
</beans>
步骤三:编写 XMLParse 工具类,用于解析 springmvc.xml,得到要扫描的包
package com.li.myspringmvc.xml;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;
/**
* @author 李
* @version 1.0
* XMLParse用于解析spring配置文件
*/
public class XMLParse {
public static String getBasePackage(String xmlFile) {
SAXReader saxReader = new SAXReader();
//maven的类路径是在target/li-springmvc/WEB-INF/classes/目录下
//通过类的加载路径-->获取到spring配置文件[对应的资源流]
InputStream inputStream =
XMLParse.class.getClassLoader().getResourceAsStream(xmlFile);
try {
//得到配置文件的文档
Document document = saxReader.read(inputStream);
Element rootElement = document.getRootElement();
Element componentScanElement = rootElement.element("component-scan");
Attribute attribute = componentScanElement.attribute("base-package");
String basePackage = attribute.getText();
return basePackage;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
}
步骤四:开发MyWebApplicationContext,充当原生Spring容器,得到扫描类的全路径列表
即把指定目录包括子目录下的 java 类的全路径扫描到 ArrayList 集合中,以便之后反射。是否需要反射,还要取决于类中是否添加了@Controller注解
(1)MyWebApplicationContext.java 实现自定义的 spring 容器,目前先完成扫描工作
package com.li.myspringmvc.context;
import com.li.myspringmvc.xml.XMLParse;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
/**
* @author 李
* @version 1.0
* MyWebApplicationContext 是我们自定义的spring容器
*/
public class MyWebApplicationContext {
//属性classFullPathList用于保存扫描包/子包的类的全路径
private List<String> classFullPathList = new ArrayList<>();
//该方法完成对自己的 spring容器的初始化
public void init() {
//返回的是我们在容器文件中配置的base-package的value
String basePackage = XMLParse.getBasePackage("myspringmvc.xml");
//这时你的 basePackage是像 com.li.controller,com.li.service 这样子的
//通过逗号进行分割包
String[] basePackages = basePackage.split(",");
if (basePackages.length > 0) {
//遍历这些包
for (String pack : basePackages) {
scanPackage(pack);
}
}
System.out.println("扫描后的路径classFullPathList=" + classFullPathList);
}
/**
* 该方法完成对包的扫描
* @param pack 表示要扫描的包,如 "com.li.controller"
*/
public void scanPackage(String pack) {
//得到包所在的工作路径[绝对路径]
// (1)通过类的加载器,得到指定包的工作路径[绝对路径]
// (2)然后用斜杠代替点=>如 com.li.controller=>com/li/controller
URL url =
this.getClass().getClassLoader()
.getResource("/" + pack.replaceAll("\\.", "/"));
// url=file:/D:/IDEA-workspace/li-springmvc/target/li-springmvc
// /WEB-INF/classes/com/li/controller/
//System.out.println("url=" + url);
//根据得到的路径,对其进行扫描,把类的全路径保存到 classFullPathList属性中
String path = url.getFile();
System.out.println("path=" + path);
//在io中,把目录也视为一个文件
File dir = new File(path);
//遍历 dir目录,因为可能会有[多个文件/子目录]
File[] files = dir.listFiles();
for (File file : files) {
if (file.isDirectory()) {
//如果是目录,需要递归扫描
//pack加上下一级的目录名继续下一层的扫描
scanPackage(pack + "." + file.getName());
} else {
//这时得到的文件可能是.class文件,也可能是其他文件
//就算是class文件,还需要考虑是否要注入到容器的问题
//目前先把所有文件的全路径都保存到集合中,后面注入对象到spring容器时再考虑过滤
String classFullPath =
pack + "." + file.getName().replaceAll(".class", "");
classFullPathList.add(classFullPath);
}
}
}
}
(2)通过 MyDispatcherServlet 前端控制器来调用并初始化 spring 容器
//添加init方法,用于初始化spring容器
@Override
public void init() throws ServletException {
MyWebApplicationContext myWebApplicationContext = new MyWebApplicationContext();
myWebApplicationContext.init();
}
(3)启动tomcat,后台成功获取到了路径,测试成功。
tomcat启动--加载了MyDispatcherServlet--通过该Servlet的init()生命周期方法初始化自定义的 spring 容器,同时调用自定义 spring 容器的 init 方法去扫描包
步骤五:完善MyWebApplicationContext(自定义 spring 容器),实例化对象到容器中
将扫描到的类,在满足添加了注解的情况下,通过反射注入到 ioc 容器
(1)部分代码:在MyWebApplicationContext中添加新属性 ioc 和新方法 executeInstance,修改init方法。
//定义属性ioc,用于存放反射生成的 bean对象(单例的)
public ConcurrentHashMap<String, Object> ioc = new ConcurrentHashMap<>();
/**
* 该方法完成对自己的 spring容器的初始化
*/
public void init() {
//返回的是我们在容器文件中配置的base-package的value
String basePackage = XMLParse.getBasePackage("myspringmvc.xml");
//这时你的 basePackage是像 com.li.controller,com.li.service 这样子的
//通过逗号进行分割包
String[] basePackages = basePackage.split(",");
if (basePackages.length > 0) {
//遍历这些包
for (String pack : basePackages) {
scanPackage(pack);
}
}
System.out.println("扫描后的路径classFullPathList=" + classFullPathList);
//将扫描到的类反射到ioc容器
executeInstance();
System.out.println("扫描后的ioc容器=" + ioc);
}
//...
/**
* 该方法将扫描到的类,在满足条件的情况下进行反射,并放入到ioc容器中
*/
public void executeInstance() {
//是否扫描到了类
if (classFullPathList.size() == 0) {//没有扫描到类
return;
}
//遍历 classFullPathList,进行反射
try {
for (String classFullPath : classFullPathList) {
Class<?> clazz = Class.forName(classFullPath);
//判断是否要进行反射(即是否添加了注解)
if (clazz.isAnnotationPresent(Controller.class)) {
Object instance = clazz.newInstance();
//获取该对象的id,默认情况下为类名(首字母小写)
String beanName = clazz.getSimpleName().substring(0, 1).toLowerCase()
+ clazz.getSimpleName().substring(1);
String value = clazz.getAnnotation(Controller.class).value();
if (!"".equals(value)) {//如果注解的value指定了id
beanName = value;
}
ioc.put(beanName, instance);
}//如果有其他注解,可以进行扩展
}
} catch (Exception e) {
e.printStackTrace();
}
}
(2)启动tomcat,反射成功。
步骤六:完成请求URL和控制器方法的映射关系
(1)MyHandler 保存url,控制器,控制器找中的方法,三者对应的映射关系。一个 MyHandler 对象就是一个映射关系。
package com.li.myspringmvc.handler;
import java.lang.reflect.Method;
/**
* @author 李
* @version 1.0
* MyHandler对象用于记录 请求的url 和 控制器方法的映射关系
*/
public class MyHandler {
private String url;//正确的url
private Object controller;//需要调用的控制器
private Method method;//控制器中url对应的方法
public MyHandler(String url, Object controller, Method method) {
this.url = url;
this.controller = controller;
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
@Override
public String toString() {
return "MyHandler{" +
"url='" + url + '\'' +
", controller=" + controller +
", method=" + method +
'}';
}
}
(2)MyDispatcherServlet.java 增加集合 handlerList,用于保存映射关系。 initHandlerMapping() 方法将映射保存到集合 handlerList 中。
这里的 initHandlerMapping() 对应原生的 HandlerMapping 映射处理器,只是将其简化为了一个方法
package com.li.myspringmvc.servlet;
import com.li.myspringmvc.annotation.Controller;
import com.li.myspringmvc.annotation.RequestMapping;
import com.li.myspringmvc.context.MyWebApplicationContext;
import com.li.myspringmvc.handler.MyHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
/**
* @author 李
* @version 1.0
* 1.MyDispatcherServlet充当原生的 DispatcherServlet,它的本质就是一个Servlet
* 因此继承 HttpServlet
*/
public class MyDispatcherServlet extends HttpServlet {
//定义属性 handlerList,保存 MyHandler对象[url和控制器方法的映射关系]
private ArrayList<MyHandler> handlerList = new ArrayList<>();
//定义ioc容器
MyWebApplicationContext myWebApplicationContext = null;
@Override
public void init() throws ServletException {
//初始化ioc容器
myWebApplicationContext = new MyWebApplicationContext();
myWebApplicationContext.init();
//调用 initHandlerMapping(),完成url和控制器方法的映射
initHandlerMapping();
//测试输出 handlerList
System.out.println("handlerList输出的结果=" + handlerList);
}
//doGet方法...
//doPost方法...
//该方法完成url和控制器方法的映射关联
private void initHandlerMapping() {
//判断当前的ioc容器是否为空
if (myWebApplicationContext.ioc.isEmpty()) {
//如果为空,就退出
return;
}
//如果不为空,就遍历ioc容器的 bean对象,进行url映射处理
//map的遍历
Set<Map.Entry<String, Object>> entries = myWebApplicationContext.ioc.entrySet();
for (Map.Entry<String, Object> entry : entries) {
//先取出 bean的clazz对象
Class<?> clazz = entry.getValue().getClass();
//如果bean对象是一个Controller
if (clazz.isAnnotationPresent(Controller.class)) {
//取出所有的方法
Method[] declaredMethods = clazz.getDeclaredMethods();
//遍历所有的方法
for (Method declaredMethod : declaredMethods) {
//如果该方法有 @RequestMapping注解
if (declaredMethod.isAnnotationPresent(RequestMapping.class)) {
//如果有,就取出@RequestMapping注解的value值,即该方法的映射路径
String url =
declaredMethod.getAnnotation(RequestMapping.class).value();
//创建 MyHandler对象,一个 MyHandler 对象就是一个映射关系
MyHandler myHandler =
new MyHandler(url, entry.getValue(), declaredMethod);
//handlerList 集合保存映射关系
handlerList.add(myHandler);
}
}
}
}
}
}
(3)启动 tomcat,输出如下,测试成功。
handlerList输出的结果=[MyHandler{url='/monster/list', controller=com.li.controller.MonsterController@d76112f, method=public void com.li.controller.MonsterController.listMonster(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)}]
步骤七:完成 MyDispatcherServlet 分发请求到对应的控制器方法
(1)MyDispatcherServlet
增加方法 getMyHandler(),该方法根据用户的请求 url 找到对应的控制器方法,并返回对应的MyHandler对象(即映射关系)
增加 executeDispatch(),该方法完成分发请求。然后 doGet 或 doPost 方法调用 executeDispatch()
部分代码:
package com.li.myspringmvc.servlet;
//import ....
/**
* @author 李
* @version 1.0
* 1.MyDispatcherServlet充当原生的 DispatcherServlet,它的本质就是一个Servlet
* 因此继承 HttpServlet
*/
public class MyDispatcherServlet extends HttpServlet {
//定义属性 handlerList,保存 MyHandler对象[url和控制器方法的映射关系]
private ArrayList<MyHandler> handlerList = new ArrayList<>();
//init方法..略..
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//System.out.println("MyDispatcherServlet doPost() 被调用..");
//调用方法,完成分发请求
executeDispatch(req, resp);
}
//initHandlerMapping方法..略..
/**
* 通过request对象的url匹配 MyHandler对象的url,如果没有就返回404
* 如果匹配就反射调用对应的方法
*/
public MyHandler getMyHandler(HttpServletRequest request) {
//获取用户请求 url
//这里的 requestURL为 /web工程路径/xxx 形式的
String requestURL = request.getRequestURI();
//方案一:切割掉前面的 web工程路径
int length = getServletContext().getContextPath().length();
requestURL = requestURL.substring(length);
System.out.println("requestURL=" + requestURL);
//方案二:tomcat直接配置项目工程路径为 /
//方案三:保存 MyHandler对象时的 url 连项目工程路径一起保存
//遍历 handlerList
for (MyHandler myHandler : handlerList) {
//如果 requestURI和集合中的某个url相等
if (requestURL.equals(myHandler.getUrl())) {
//返回这个对象
return myHandler;
}
}
//如果没有匹配,即返回null
return null;
}
//编写方法,完成分发请求
private void executeDispatch(HttpServletRequest request, HttpServletResponse response) {
MyHandler myHandler = getMyHandler(request);
try {
//如果 myHandler为 null,说明请求 url没有匹配的方法,即用户请求的资源不存在
if (myHandler == null) {
response.getWriter().print("<h1>404 NOT FOUND</h1>");
} else {//匹配成功,就反射调用控制器的方法
myHandler.getMethod()
.invoke(myHandler.getController(), request, response);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
(2)启动tomcat,浏览器中分别访问:
测试成功。至此,任务2的目标功能实现完毕。
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO