单节内容
第一节
开发工具和Java语言介绍
主要介绍项目所需要的开发工具,并且会简单回顾这个项目所用到的语言-java,语法基础,控制流,数据结构,面向对象,异常,随机数等。
第二节
Spring入门,模板语法和渲染
主要结合Spring进行入门介绍,包括参数解析,HTTP Method,AOP等等。
第三节
数据库交互MyBatis集成
主要对业务的字段进行设计,数据库的创建,数据库的交互等,并会介绍注解和XML定义以及首页的开发。
第四节
用户注册登录管理
主要实现注册,登录,浏览等基本功能,并且会考虑到数据安全性等。
第五节
资讯发布,图片上传,资讯首页
主要实现资讯的发布,图片的上传,完成资讯首页的搭建。
第六节
评论中心,站内信
主要搭建资讯详情页,实现评论,站内信等功能。
第七节
redis入门以及redis实现赞踩功能
主要讲解Redis,带你入门以及redis实现赞踩功能。
第八节
异步设计和站内邮件通知系统
主要进行异步涉及和搭建站内邮件通知系统,实现邮件的发送功能。
第九节
多种资讯排序算法 2
主要讲述多种资讯排序算法以及多线程的讲解。
第十节
JavaWeb项目测试和部署,课程总结回顾
主要进行整个项目的测试以及打包,部署,并且会对整个项目进行一个总结和扩展,讲述面试中怎样讲解项目以及包装。
源码分析
1. aspect
1.1 LogAspect
1 |
|
1) @Component
使用@Component
标记为IOC容器中的组件
2) Logger LOG = LoggerFactory.getLogger()
用Logger工厂获取Logger实例
3) JoinPoint 对象
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:
方法名 | 功能 |
---|---|
Signature getSignature() | 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息 |
Object[] getArgs() | 获取传入目标方法的参数对象 |
Object getTarget() | 获取被代理的对象 |
Object getThis() | 获取代理对象 |
2. async
异步点赞
为什么异步
点赞,回复评论的时候,表面上是赞数增加了,其实还有很多其他的工作要做。比如,对方要收到消息提醒,成就值增加。一些行为会引起一系列连锁反应。如果在点赞时立马处理,会影响程序运行效率。而且会造成代码冗余,比如发布新闻,和回复评论都可以使得成就值增加,如果都跟着写在后面的代码里会把成就值增加这段代码写两遍,所以大型服务需要服务化和异步化。
- 服务化
服务化:某一个单独的业务独立成一个工程,提供接口。不只是service层的一个类。
暴露一些接口,比如数据库服务,如果一个部门要去数据库查询,小公司可能写个SQL语句。对于大公司,需要一个组单独做数据库服务,暴露接口给别的部门用。好处是防止别的部门有数据库权限,数据库单独有一个组维护,出问题找他们运维就好。 - 异步化
异步化:用户点赞,用户首先要知道的是这个赞已经点上了。用户提交Oj,用户要立马知道的是代码有没有通过。而后面应该的东西,比如积分增加了,用户不会有立马想知道的需求,如果间隔几秒钟在更新,用户也不会有很大的意见。
概述
在一个网站中,一个业务发生的同时,还有一些后续业务需要发生。
比如点赞,除了完成点赞功能外,还有一系列,比如提醒被点赞的用户等等,为了能够实现这些操作并且不拖慢单纯点赞功能的实现,我们将这些使用异步队列实现。
处理流程如下图:
- Biz(生产)
Biz为业务
部门,理解为点赞的实现,也就是在实现点赞的同时通过EventProducer发送一个事件 - 进入队列
这个事件进入队列等待,队列另一头,有一个EventConsumer,不断消费事件 - EventHandler(消费)
EventConsumer下面有很多EventHandler,只要EventHandler发现自己需要处理的事件类型,就会进行相应的操作。
优点:①后续业务的实现,不会拖慢主业务。②如果后续业务的服务器挂掉,只要重启,继续从优先队列消费事件即可。
2.1 LikeHandler
记得开启Rrdis—redis-server.exe redis.windows.conf
具体的执行动作,具体的实现类,这个是点赞后要执行的行为,给别人发提醒。
1 |
|
1)参考 Spring@Autowired注解与自动装
Spring 2.5 引入了 @Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 通过 @Autowired的使用来消除 set ,get方法。
- 事先在 Spring 容器中声明
Spring 通过一个 BeanPostProcessor 对 @Autowired 进行解析,所以要让 @Autowired 起作用必须事先在 Spring 容器中声明AutowiredAnnotationBeanPostProcessor
Bean。
1 | <!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 --> |
修改在原来注入spirng容器中的bean的方法
修改在原来注入spirng容器中的bean的方法:在域变量上加上标签@Autowired,并且去掉 相应的get 和set方法也去掉
在applicatonContext.xml中 把原来 引用的标签也去掉。
2.2 LoginExceptionHandler
1 |
|
2.3 EventConsumer
解决的问题
如何将活动分发下去给相关的所有handle实现。
步骤
消费活动,在初始化前,先得到Handler接口所有的实现类,遍历实现类。
通过getSupportEventType得到每个实现类对应处理的活动类型。反过来记录在config哈希表中,config中的key是活动的类型,比如说是LIKE,COMMENT,是枚举里的成员,value是一个ArrayList的数组,里面存放的是各种实现方法。见代码中的。当从队列中获得一个活动时,这里用的是从右向外pop()一个活动实体。进行解析。这里的config.get(eventModel.getType())是一个数组,里面存放着所有关于这个活动要执行的实现类。遍历这个数组,开始执行实现类里的方法。
一些注释
implements InitializingBean
,@Override afterPropertiesSet()
InitializingBean 通过实现此接口的afterPropertiesSet()方法记录哪些Event需要哪些handler来处理implements ApplicationContextAware
ApplicationContextAware 通过实现此接口的setApplicationContext方法获取上下文Map<EventType, List<EventHandler>> config = new HashMap<>();
用来存储一个事件类型对应的所有的eventhandler,下次有该事件产生时,即可直接调用对应的listMap<String, EventHandler> beans = applicationContext.getBeansOfType(EventHandler.class);
找出上下文中所有实现了EventHandler接口的类,存入beansif (beans != null)……
遍历所有的handler,将他们存入他们所监听的eventType对应的list中List<String> messages = jedisAdapter.brpop(0, key);
从redis的队列中取出事件,并存入list中for (String message : messages)
遍历取出的事件
7.1if (message.equals(key))
第一个元素是队列名字,跳过
7.2if (!config.containsKey(eventModel.getType()))
跳过不能处理的事件
7.3for (EventHandler handler : config.get(eventModel.getType()))
处理他的所有的handler
1 | @Service |
2.4 EventHandler
设计为一个接口,handler都实现此接口。
1 | public interface EventHandler { |
2.5 EventModel
即发送的队列的事件模型,只有一些基本属性和get、set方法。
其中一些set的return 设置为this,是因为方便连续set多个属性。
1 | public class EventModel { |
2.6 EventProducer
活动生产者,相当于生产消费者中的生产者,在controller层执行一个动作后,用这个类把需要异步的信息打包好,放进Redis的队列中。放入是把EventModel序列化为JSON,存入Redis的列表中。
1 |
|
1) JSON
由于 JSON 语法是 JavaScript 语法的子集,JavaScript 函数 eval() 可用于将 JSON 文本转换为 JavaScript 对象。
概览
JSON(JavaScript Object Notation)
是一种轻量级的数据交换格式。- JSON 是存储和交换文本信息的语法。类似 XML。
- JSON 比 XML 更小、更快,更易解析。
为什么使用 JSON?
对于 AJAX 应用程序来说,JSON 比 XML 更快更易使用:
使用 XML
- 读取 XML 文档
- 使用 XML DOM 来循环遍历文档
- 读取值并存储在变量中
使用 JSON
- 读取 JSON 字符串
- 用
eval()
处理 JSON 字符串
书写格式
JSON 数据的书写格式是:名称/值对。
名称/值对包括字段名称(在双引号中),后面写一个冒号,然后是值:“firstName” : “John”
这很容易理解,等价于这条 JavaScript 语句:firstName = “John”
json嵌套
对于json嵌套,只要记住
- 符号
:
”前是键,符号后是值 - 大括号成对找
一层层剥开,就清楚了。
2)前后台的传输
- JSON.parseObject,是将Json字符串转化为相应的对象
- JSON.toJSONString则是将对象转化为Json字符串。
2.7 EventType
EventType 是获得活动的类型,可以有点赞,评论,登陆等待
1 | public enum EventType { |
3. configuration
3.1. ToutiaoWebConfiguration
1 |
|
1)spring boot中使用拦截器
1、注册拦截器
创建一个类MyWebConfig继承WebMvcConfigurerAdapter
,并重写addInterceptors
方法
多个拦截器组成一个拦截器链
- addPathPatterns
添加拦截规则 - excludePathPatterns
排除拦截
1 | @Configuration |
2、自定义拦截器
创建一个自定义拦截器MyiInterceptor实现HandlerInterceptor接口
,重写所有的方法
实现自己的业务(见下面的章节–)
4. controller
4.1. HomeController
1 |
|
4.2. IndexController
1 | //@Controller |
1)model.addAttribute("k",v)
model.addAttribute(“editPageFlg”,editPageFlg)的作用:类似于hashmap。
向Map里面添加键值对,key=”editPageFlg”,value=editPageFlg。
此类来源于ModelMap的定义,
1 | public class ModelMap extends LinkHashMap<String,Object> |
其中addAttribute的源码为:
1 | public ModelMap addAttribute(String attributeName, Object attributeValue){ |
在put之前,会进行判空检测。这就是addAttribute与put的区别。
2)@CookieValue
@CookieValue的作用
用来获取Cookie中的值
@CookieValue参数
1、value:参数名称
2、required:是否必须
3、defaultValue:默认值
3)用 JSP 设置 Cookies
用 JSP 设置 Cookies 包括三个步骤:
- (1) 创建一个 Cookie 对象
用 cookie 的名称和值调用 cookie 构造函数,名称和值是字符串。
1 | Cookie cookie = new Cookie("key","value"); |
这个名字和值都不应该包含空格或任何以下字符:[ ] ( ) = , " / ? @ : ;
- (2) 设置最大持续时间
使用setMaxAge
指定 cookie 的有效期是多长时间(以秒为单位)。以下是建立了一个持续 24 小时的 cookie。
1 | cookie.setMaxAge(60*60*24); |
- (3) 将 cookie 发送到 HTTP 响应标题中
使用response.addCookie
在 HTTP 响应标题中添加 cookies,如下所示:
1 | response.addCookie(cookie); |
4)request和response方法的总结
Request
JSP中的隐藏对象 – request
request
可以在JSP网页中使用,在转译为Servlet之后,它会转换为javax.servlet.http.HttpServletRequest
型态的对象,HttpServletRequest对象是有关于客户端所发出的请求之对象,只要是有关于客户端请求的信息,都可以藉由它来取得,例如请求标头、请求方法、请求参数、使用者IP等等信息。
方法 | 作用 |
---|---|
getParameterNames() | 取得客户端所发出的请求参数名称 |
getParameter() | 可以让您指定请求参数名称,以取得对应的设定值 |
getServerName() | 请求的服务器 |
getProtocol() | 使用协议 |
getMethod() | 请求方法 |
getServerPort() | 请求端口号 |
getContextPath() | Context路径. context理解为上下文比较好(也就是一个项目) |
getServletPath() | Servlet路径 |
getRequestURI() | URI路径 |
getQueryString() | 查询字符串 |
getRemoteAddr() | 使用者主机IP |
getRemotePort() | 使用者使用端口号 |
response
JSP中的隐藏对象 –response
JSP的response
隐藏对象在转换为Servlet之后,对应于HttpServletResponse型态对象,HttpServletResponse
对象是有关于对客户端请求之响应,您可以利用它来设定一些要响应的讯息,例如标题信息、响应状态码等.
|方法|作用|
|—|—|
|setHeader()|是一个通用的标头设定方法,您可以用它来设定任何「名称/值」的标头|
|setIntHeader()|是专门用来设定整数值标头的版本|
|setDateHeader()|是setHeader()的Date设定版本,第二个参数是设定Date的Long数值,0表示GMT 1970/1/1 00:00。
|setStatus()|是用来设定回应的状态码,例如404 Not Found,HttpServletResponse类中提供了一些助忆常数设定,例如SC_NOT_FOUND就是表示404状态码(可以在Servlet API文件中查询相关的助忆常数)|
|sendError()|会根据服务器的预设错误网页回报方式显示错误讯息|
|sendRedirect()|设置重定向页面|
|getWriter()|取得PrintWriter对象,由它来写出响应至服务器的本体信息|
5)HttpServletResponse和HttpServletRequest
HttpServletResponse和HttpServletRequest
Request
Request是Servlet.service()方法的一个参数,类型为javax.servlet.http.HttpServletRequest
。在客户端发出每个请求时,服务器都会创建一个request对象,并把请求数据封装到request中,然后在调用Servlet.service()方法时传递给service()方法,这说明在service()方法中可以通过request对象来获取请求数据
Request的功能可以分为以下几种:
- 封装了请求头数据
- 封装了请求正文数据,如果是GET请求,那么就没有正文
- request是一个域对象,可以把它当成Map来添加获取数据
- request提供了请求转发和请求包含功能
Response
Response是Servlet.service方法的一个参数,类型为javax.servlet.http.HttpServletResponse
。在客户端发出每个请求时,服务器都会创建一个response对象,并传入给Servlet.service()方法。response对象是用来对客户端进行响应的,这说明在service()方法中使用response对象可以完成对客户端的响应工作
response对象的功能分为以下四种:
- 设置响应头信息
- 发送状态码
- 设置响应正文
- 重定向
6)numeration接口
Enumeration是java.util中的一个接口类,在Enumeration中封装了有关枚举数据集合的方法,与Iterator差不多,用来遍历集合中的元素 但是枚举Enumeration只提供了遍历Vector和Hashtable
类型集合元素的功能,这种类型的集合对象通过调用elements()方法获取一个Enumeration对象 然后Enumeratino对象再调用以下方法来对集合中的元素进行遍历。
1 | package java.util; |
方法 | 描述 |
---|---|
boolean hasMoreElements( ) | 测试此枚举是否包含更多的元素 |
Object nextElement( ) | 如果此枚举对象至少还有一个可提供的元素,则返回此枚举的下一个元素 |
7)Iterator接口
1 | package java.util; |
8) Spring MVC 重定向常用处理方式
Controller 视图方法间的跳转,无非就是带参跳转和不带参跳转。常用的方法有通过 String 映射 RequestMapping
实现重定向,或者通过 ModelAndView
对象,又或者是 RedirectView
对象,下面逐一说明。
String 重定向
是 return 映射到另一个 Controller 方法的字符串。如果有请求参数,就拼接在 RequestMapping 映射的字符串后面。
1 | // 返回字符串映射的方式 |
ModelAndView 重定向
另一种方法是通过返回 ModelAndView
对象来实现跳转。类似的,如果有请求参数,也可以通过类似 GET 参数拼接的方式:
1 | // 返回 ModelAndView 对象 |
RedirectView 重定向
还有一种方法是通过返回 RedirectView
对象实现跳转,该方法和上面的不同之处在于,RedirectView
对象不需要设置 redirect 前缀:
1 | // 返回 RedirectView 对象 |
4.3. LikeController
1 |
|
4.4. LoginController
1 |
|
4.5 MessageController
1 |
|
4.6 NewsController
1 |
|
4.7. SettingController
1 |
|
1)@RequestBody
- 1.不使用@RequestBody注解
相当于使用该注解,并required默认为true
①当前端没有传参时,会报错400
②当前端传一个空{},对象会根据构造函数自动生成。 - 2.只使用@RequestBody注解
效果同1 - 3.使用@RequestBody(required = false)
可以不传参,但句柄会为null
2)@ResponseBody
- 作用:
该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区。 - 使用时机:
返回的数据不是html标签的页面
,而是其他某种格式的数据时(如json、xml等)使用;
5. DAO
5.1 CommentDAO
1 |
|
1)DAO在JavaWeb开发中的定位
一个典型的DAO实现有下列几个组件:
1.一个DAO接口(CRUD
)
2.一个实现DAO接口的具体类
3.数据传递对象(DTO)(POJO
):有些时候叫做值对象(VO)或领域模型(domain)
2)@Mapper注解
作用:持久化
- 一种持久化方式:
在一个包中写一个DAO的接口,在另一个包里面写DAO的实现,使用sqlMapClient来从***-sql.xml中读取相应的sql。 - spring+Mybatis的项目,一种新的持久化方式:
只写一个dao的接口,在接口的方法中直接注解上用到的sql语句,接口上方多了一个@Mapper注解
。
5.2 LoginTicketDAO
1 |
|
5.3 MessageDAO
1 |
|
5.4 NewsDAO
1 |
|
5.5 UserDAO
1 |
|
6. interceptor
6.1 LoginRequiredInterceptor
1 |
|
1)拦截器(Interceptor)
作用
在Web开发中,拦截器(Interceptor)可以用来验证是否登录
、预先设置数据
以及统计方法的执行效率
等。
分类
Spring中的拦截器分两种,一是HandlerInterceptor,另一个是MethodInterceptor。这里主要说以下HandlerInterceptor。
HandlerInterceptor是SpringMVC项目中的拦截器,拦截目标是请求的地址
,比MethodInterceptor先执行。实现一个HandlerInterceptor拦截器可以直接实现该接口,也可以继承HandlerInterceptorAdapter类。
SpringMVC处理请求过程
SpringMVC处理请求的整个过程是
- 先根据请求找到对应的
HandlerExecutionChain
,它包含了处理请求的handler和所有的HandlerInterceptor拦截器 - 然后在调用hander之前分别调用
每个HandlerInterceptor拦截器
的preHandle
方法
2.1 若有一个拦截器返回false,则会调用triggerAfterCompletion
方法,并且立即返回不再往下执行
2.2 若所有的拦截器全部返回true并且没有出现异常,则调用handler返回ModelAndView对象
;再然后分别调用每个拦截器的postHandle
方法;最后,即使是之前的步骤抛出了异常,也会执行triggerAfterCompletion
方法。
多拦截器工作流程:
需要Override的三种方法
(1 )preHandle (HttpServletRequest request, HttpServletResponse response, Object handle)
controller 执行之前调用
该方法将在请求处理之前进行调用。SpringMVC 中的Interceptor 是链式调用的,在一个请求中可以同时存在多个Interceptor 。每个Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求的一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值Boolean 类型的,当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法。
(2 )postHandle (HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView)
controller 执行之后,且页面渲染之前调用
这个方法包括后面要说到的afterCompletion 方法都只能是在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用。postHandle 方法,是在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图渲染之前被调用,所以我们可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作。postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行。
(3 )afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex)
页面渲染之后调用,一般用于资源清理操作。
该方法也是需要当前对应的Interceptor 的preHandle 方法的返回值为true 时才会执行。该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。这个方法的主要作用是用于进行资源清理工作的。
在Spring Boot中配置拦截器,需要写一个配置类继承WebMvcConfigurerAdapter
类并添加该拦截器(见2)
1 | @Component |
6.2 PassportInterceptor
1 |
|
7. model
7.1 Comment
1 | public class Comment { |
7.2 EntityType
1 | public class EntityType { |
7.3 HostHolder
1 |
|
7.4 LoginTicket
1 | public class LoginTicket { |
7.5 Message
1 | public class Message { |
7.6 News
1 | public class News { |
7.7 User
1 | public class User { |
7.8 ViewObject
1 | public class ViewObject { |
8. service
8.1 CommentService
1 |
|
8.2 LikeService
1 |
|
8.3 MessageService
1 | public class MessageService { |
8.4 NewsService
1 |
|
8.5 QiniuService
1 |
|
8.6 ToutiaoService
1 |
|
8.7 UserService
1 |
|
9. util
9.1 JedisAdapter
利用JSON进行对象序列化和反序列化,JSON存到Redis中,可以做在在Redis中存储对象。
1 | //将一个对象转换为一个jsoon串存入set中 |
1 |
|
1 |
|
9.2 MailSender
1 |
|
9.3 RedisKeyUtil
1 | public class RedisKeyUtil { |
9.4 ToutiaoUtil
1 | public class ToutiaoUtil { |
10. ToutiaoApplication
1 |
|
spring 的SpringApplication
作用:入口类
Spring应用的入口类是Spring应用的配置起点,是配置Spring上下文的起点,往往使用了@SpringBootApplication
或@EnableAutoConfiguration
等标注类。
在Spring应用的入口类中往往只有一个main()方法,这虽然与标准的Java应用保持了一致,但在有些时候会让开发人员觉得困惑。
在Spring应用的入口类中的main()方法中,往往只是简单地调用Spring Boot的SpringApplication类的run()
方法,以启动该Spring应用。
1 | SpringApplication.run(MySpringConfigurationApp.class, args); |
Spring Boot的SpringApplication类
Spring Boot的SpringApplication类,用以启动一个Spring应用
,实质上是为Spring应用创建并初始化Spring上下文
。
SpringApplication类的run()
方法默认返回一个ConfigurableApplicationContext对象。
11. 配置文件及模板
11.1 NewsDAO.xml
1 | <?xml version="1.0" encoding="UTF-8" ?> |
MyBatis的Mapper XML 文件
MyBatis 的真正强大在于它的映射语句,也是它的魔力所在。
详细请见官方文档
SQL 映射顶级元素(按照它们应该被定义的顺序)
cache – 给定命名空间的缓存配置
cache-ref – 其他命名空间缓存配置的引用
resultMap – 是最复杂也是最强大的元素,用来描述如何从数据库结果集中来加载对象
sql – 可被其他语句引用的可重用语句块
insert – 映射插入语句
update – 映射更新语句
delete – 映射删除语句
select – 映射查询语句
属性
属性 | 描述 |
---|---|
id | 在命名空间中唯一的标识符,可以被用来引用这条语句 |
parameterType | 将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过 TypeHandler 推断出具体传入语句的参数,默认值为 unset |
parameterMap | 这是引用外部 parameterMap 的已经被废弃的方法。使用内联参数映射和 parameterType 属性 |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。使用 resultType 或 resultMap,但不能同时使用 |
11.2 application.properties
1 | spring.datasource.url=jdbc:mysql://localhost:3306/toutiao?useUnicode=true&characterEncoding=utf8&useSSL=false |
11.3 mybatis-config.xml
1 | <?xml version="1.0" encoding="UTF-8"?> |
11.4 toolbox.xml
1 | <toolbox> |
- velocity-tools 提供了很多实用的 Java 类,使用这些小工具前,需要在 web.xml 中配置 toolbox.xml 文件,在 VelocityViewServlet 后加入另一个参数:
1 | <init-param> |
这个参数指定了 toolbox.xml 的位置,通常我们把配置文件放在 WEB-INF 下。
12. test
12.1 InitDatabaseTests
1 | @RunWith(SpringJUnit4ClassRunner.class) |
1)SpringBoot Web项目中中如何使用Junit
- 创建一个普通的Java类,在Junit4中不再需要继承TestCase类了
- 因为我们是Web项目,所以在创建的Java类中添加注解:
注解 | 作用 |
---|---|
@RunWith(SpringJUnit4ClassRunner.class) | SpringJUnit支持,由此引入Spring-Test框架支持 |
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class) | 指定我们SpringBoot工程的Application启动类 |
@WebAppConfiguration | 由于是Web项目,Junit需要模拟ServletContext,因此我们需要给我们的测试类加上@WebAppConfiguration |
- 接下来就可以编写测试方法了,测试方法使用@Test注解标注即可。
2)随机数—random.nextInt(1000)
java中一般有两种随机数,一个是Math中random()方法,一个是Random类。
一、Math.random()
调用Math.Random()函数能够返回带正号的double值
,该值大于等于0.0且小于1.0,即取值范围是[0.0,1.0)的左闭右开区间
二、Random类
在进行随机时,随机算法的起源数字称为种子数(seed),在种子数的基础上进行一定的变换,从而产生需要的随机数字。
相同种子数的Random对象,相同次数生成的随机数字是完全相同的。也就是说,两个种子数相同的Random对象,第一次生成的随机数字完全相同,第二次生成的随机数字也完全相同。
|Random类中的构造方法|作用|
|—|—|
|Random random = new Random();|默认构造方法|
|Random random = new Random(1000);|指定种子数字|
Random类中各方法生成的随机数字都是均匀分布的,也就是说区间内部的数字生成的几率是均等的。
Random类中的常用方法 | 作用 |
---|---|
public boolean nextBoolean() | 该方法的作用是生成一个随机的boolean值,生成true和false的值几率相等,也就是都是50%的几率 |
public double nextDouble() | 该方法的作用是生成一个随机的double值,数值介于[0,1.0)之间,这里中括号代表包含区间端点,小括号代表不包含区间端点,也就是0到1之间的随机小数,包含0而不包含1.0 |
public int nextInt() | 该方法的作用是生成一个随机的int值,该值介于int的区间,也就是-2的31次方到2的31次方-1之间 |
public int nextInt(int n) | 该方法的作用是生成一个随机的int值,该值介于[0,n) 的区间,也就是0到n之间的随机int值,包含0而不包含n |
public void setSeed(long seed) | 该方法的作用是重新设置Random对象中的种子数。设置完种子数以后的Random对象和相同种子数使用new关键字创建出的Random对象相同 |
12.2 JedisTests
1 | (SpringJUnit4ClassRunner.class) |
12.3 LikeServiceTests
1 | (SpringJUnit4ClassRunner.class) |
12.4 测试多线程
1 | class MyThread extends Thread { |
12.5 ToutiaoApplicationTests
1 | (SpringJUnit4ClassRunner.class) |
12.6 init-schama.sql
1 | DROP TABLE IF EXISTS `user`; |
手动初始化:
1 | insert user(name,password,salt,head_url) values('user1','111111','','http://images.nowcoder.com/head/111t.png'); |
手动初始化toutiao2:
1 | DROP TABLE IF EXISTS `user`; |
1 | insert user(name,password,salt,head_url) values('user1','111111','','http://images.nowcoder.com/head/111t.png'); |