├── 00-01.md
├── img
├── 00-03
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ └── 04.png
├── 00-04
│ ├── 01.png
│ └── 02.png
├── 00-06
│ ├── 01.png
│ └── 02.png
├── 00-07
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ └── 04.png
├── 01-02
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ ├── 04.png
│ ├── 05.png
│ └── 06.png
├── 01-03
│ ├── 01.png
│ └── 02.png
├── 01-04
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ ├── 04.png
│ ├── 05.png
│ ├── 06.png
│ ├── 07.png
│ ├── 08.png
│ └── 09.png
├── 01-06
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ ├── 04.png
│ ├── 05.png
│ ├── 06.png
│ ├── 07.png
│ ├── 08.png
│ └── 09.png
├── 01-07
│ ├── 01.png
│ ├── 02.png
│ └── 03.png
└── 01-09
│ ├── 01.png
│ ├── 02.png
│ ├── 03.png
│ └── 04.png
├── 01-01.md
├── 00-00.md
├── temp.md
├── 01-05.md
├── 01-00.md
├── 01-08.md
├── 01-10.md
├── 00-08.md
├── 00-05.md
├── README.md
├── supplement.md
├── 00-02.md
├── 01-07.md
├── 00-06.md
├── 00-03.md
├── 01-09.md
├── 01-04.md
├── 00-07.md
├── 01-03.md
├── 00-04.md
├── 01-06.md
└── 01-02.md
/00-01.md:
--------------------------------------------------------------------------------
1 | 00-01、相关软件的安装
2 | ---
3 |
4 | jdk 1.8
5 | netbeans 8.0
6 | tomcat 8.0
7 |
--------------------------------------------------------------------------------
/img/00-03/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-03/01.png
--------------------------------------------------------------------------------
/img/00-03/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-03/02.png
--------------------------------------------------------------------------------
/img/00-03/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-03/03.png
--------------------------------------------------------------------------------
/img/00-03/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-03/04.png
--------------------------------------------------------------------------------
/img/00-04/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-04/01.png
--------------------------------------------------------------------------------
/img/00-04/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-04/02.png
--------------------------------------------------------------------------------
/img/00-06/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-06/01.png
--------------------------------------------------------------------------------
/img/00-06/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-06/02.png
--------------------------------------------------------------------------------
/img/00-07/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-07/01.png
--------------------------------------------------------------------------------
/img/00-07/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-07/02.png
--------------------------------------------------------------------------------
/img/00-07/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-07/03.png
--------------------------------------------------------------------------------
/img/00-07/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/00-07/04.png
--------------------------------------------------------------------------------
/img/01-02/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-02/01.png
--------------------------------------------------------------------------------
/img/01-02/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-02/02.png
--------------------------------------------------------------------------------
/img/01-02/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-02/03.png
--------------------------------------------------------------------------------
/img/01-02/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-02/04.png
--------------------------------------------------------------------------------
/img/01-02/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-02/05.png
--------------------------------------------------------------------------------
/img/01-02/06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-02/06.png
--------------------------------------------------------------------------------
/img/01-03/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-03/01.png
--------------------------------------------------------------------------------
/img/01-03/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-03/02.png
--------------------------------------------------------------------------------
/img/01-04/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/01.png
--------------------------------------------------------------------------------
/img/01-04/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/02.png
--------------------------------------------------------------------------------
/img/01-04/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/03.png
--------------------------------------------------------------------------------
/img/01-04/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/04.png
--------------------------------------------------------------------------------
/img/01-04/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/05.png
--------------------------------------------------------------------------------
/img/01-04/06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/06.png
--------------------------------------------------------------------------------
/img/01-04/07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/07.png
--------------------------------------------------------------------------------
/img/01-04/08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/08.png
--------------------------------------------------------------------------------
/img/01-04/09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-04/09.png
--------------------------------------------------------------------------------
/img/01-06/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/01.png
--------------------------------------------------------------------------------
/img/01-06/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/02.png
--------------------------------------------------------------------------------
/img/01-06/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/03.png
--------------------------------------------------------------------------------
/img/01-06/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/04.png
--------------------------------------------------------------------------------
/img/01-06/05.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/05.png
--------------------------------------------------------------------------------
/img/01-06/06.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/06.png
--------------------------------------------------------------------------------
/img/01-06/07.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/07.png
--------------------------------------------------------------------------------
/img/01-06/08.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/08.png
--------------------------------------------------------------------------------
/img/01-06/09.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-06/09.png
--------------------------------------------------------------------------------
/img/01-07/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-07/01.png
--------------------------------------------------------------------------------
/img/01-07/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-07/02.png
--------------------------------------------------------------------------------
/img/01-07/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-07/03.png
--------------------------------------------------------------------------------
/img/01-09/01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-09/01.png
--------------------------------------------------------------------------------
/img/01-09/02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-09/02.png
--------------------------------------------------------------------------------
/img/01-09/03.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-09/03.png
--------------------------------------------------------------------------------
/img/01-09/04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/letiantian/another-tutorial-about-java-web/HEAD/img/01-09/04.png
--------------------------------------------------------------------------------
/01-01.md:
--------------------------------------------------------------------------------
1 | 01-01、Spring与面向切面编程
2 | ---
3 |
4 | 面向切面编程是一种编程模式。
5 |
6 | 使用动态代理可以实现面向切面编程。
7 |
8 | google:`java 设计模式 代理`、`java 动态代理`、`Spring AOP`、`Spring 面向切面`。
9 |
--------------------------------------------------------------------------------
/00-00.md:
--------------------------------------------------------------------------------
1 | 00-00、序
2 | ---
3 |
4 | 本文会穿插大量的链接和引用。
5 |
6 |
7 |
8 | 建议先对Java、HTML、CSS、JS、ajax、HTTP、Firebug等有所了解。
9 |
10 | 推荐一下“菜鸟教程”([http://www.runoob.com/](http://www.runoob.com/))中的相关教程(利
11 | 益无关~),很适合入门。
12 |
13 |
14 | linux下编写程序。
15 | 文件均是UTF-8编码。
16 |
--------------------------------------------------------------------------------
/temp.md:
--------------------------------------------------------------------------------
1 | ```shell
2 | echo "# another-tutorial-about-java-web" >> README.md
3 | git init
4 | git add README.md
5 | git commit -m "first commit"
6 | git remote add origin https://github.com/someus/another-tutorial-about-java-web.git
7 | git push -u origin master
8 | ```
9 |
--------------------------------------------------------------------------------
/01-05.md:
--------------------------------------------------------------------------------
1 | 01-05、JSON
2 | ---
3 |
4 | ## 如何响应JSON数据
5 |
6 | [Spring 3 MVC and JSON example](http://www.mkyong.com/spring-mvc/spring-3-mvc-and-json-example/)
7 | [Spring MVC – Easy REST-Based JSON Services with @ResponseBody](http://codetutr.com/2013/04/09/spring-mvc-easy-rest-based-json-services-with-responsebody/)
8 |
9 | ## 如何处理HTTP请求中的JSON数据
10 | [How to pass Json object from ajax to spring mvc controller?](http://stackoverflow.com/questions/20245544/how-to-pass-json-object-from-ajax-to-spring-mvc-controller)
11 |
--------------------------------------------------------------------------------
/01-00.md:
--------------------------------------------------------------------------------
1 | 01-00、Spring与依赖注入
2 | ---
3 |
4 |
5 | 依赖注入是反转控制的一种。
6 |
7 |
8 | ## 什么是反转控制?
9 |
10 | 我们平常写程序,需要什么对象,就在代码里显式地new一个出来然后使用,这是我们自己去控制对象的生成。
11 | 而反转控制是让Spring(或者类似的其他工具)帮忙去生成我们需要的对象,也就是说对象的生成的控制权交给Spring了。
12 |
13 | 当然,Spring需要依据一定的规则去生成对象,这个规则就在我们写的xml配置文件、或者代码中添加的注解之中。
14 | 换句话说,我们不要生成对象,但是要去写配置。
15 |
16 | 据说,反转控制可用于解耦。这个在小型的项目中很难看出来,项目越大越能感受得到。(我是没写过这方面的大的项目,想着xml配置就头疼)
17 |
18 | 反转控制的实现中应用了大量的反射。
19 |
20 | ## 依赖注入
21 |
22 | 声明依赖关系,Spring将对象A需要的对象B注入到对象A中。
23 |
24 |
25 | ## 建议阅读
26 |
27 | google `Spring 依赖注入`。
28 |
--------------------------------------------------------------------------------
/01-08.md:
--------------------------------------------------------------------------------
1 | 01-08、拦截器
2 | ---
3 | 拦截器(interceptor),类似servlet中的过滤器。
4 |
5 |
6 | [Spring 3 MVC Interceptor tutorial with example](http://viralpatel.net/blogs/spring-mvc-interceptor-example/)
7 | [Spring MVC Interceptors Example – HandlerInterceptor and HandlerInterceptorAdapter](http://www.journaldev.com/2676/spring-mvc-interceptors-example-handlerinterceptor-and-handlerinterceptoradapter)
8 | [Spring MVC handler interceptors example](http://www.mkyong.com/spring-mvc/spring-mvc-handler-interceptors-example/)
9 | [Spring MVC Handler Interceptor](http://javapapers.com/spring/spring-mvc-handler-interceptor/)
10 |
11 |
12 | 暂不支持注解。[Is it possible to wire a Spring MVC Interceptor using annotations?](http://stackoverflow.com/questions/4389224/is-it-possible-to-wire-a-spring-mvc-interceptor-using-annotations)
13 |
--------------------------------------------------------------------------------
/01-10.md:
--------------------------------------------------------------------------------
1 | 01-10、转换器与格式化
2 | ---
3 | 转换器:converter
4 | 格式化:Format
5 |
6 |
7 | 在[01-06、校验器](./01-06.md)、[01-09、文件上传](./01-09.md)中的例子中都使用了数据绑定
8 | (将表单数据绑定到bean对象中),例如:
9 |
10 | ```java
11 | @RequestMapping(value = "/output")
12 | public String output(Person person, Model model) {
13 | model.addAttribute("person", person);
14 | return "hello/output";
15 | }
16 | ```
17 | 表单的数据都是String类型,如果我们的bean类中的属性是其他类型,例如Date、int,这时候就需要写一个工具,将String转换成Date、int。
18 | 这就是转换器与格式化做的事情:类型转换。字符串转换成数字类型是内置的。
19 |
20 | **资料:**
21 | [8. Validation, Data Binding, and Type Conversion](http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/validation.html)
22 | [Spring MVC request parameter conversion with minimal configuration](http://unitstep.net/blog/2013/04/07/spring-mvc-request-parameter-conversion-with-minimal-configuration/)
23 | [Introduction to Spring Converters and Formatters](http://www.javabeat.net/introduction-to-spring-converters-and-formatters/)
24 |
--------------------------------------------------------------------------------
/00-08.md:
--------------------------------------------------------------------------------
1 | 00-08、Tomcat的运行机制
2 | ---
3 |
4 | 在[00-02、理解HTTP](./00-02.md)中给出了一个简单的服务器代码,Tomcat的设计思路也是类似的。
5 |
6 | Tomcat是一个servlet容器。
7 |
8 | [http://www.kaifajie.cn/tomcat6/7454.html](http://www.kaifajie.cn/tomcat6/7454.html)中的内容值得参考:
9 | > 先不去关技术细节,对一个servlet容器,我觉得它首先要做以下事情:
10 | 1:实现Servlet api规范。这是最基础的一个实现,servlet api大部分都是接口规范。如request、response、session、cookie。为了我们应用端能正常使用,容器必须有一套完整实现。
11 | 2:启动Socket监听端口,等待http请求。
12 | 3:获取http请求,分发请求给不同的协议处理器,如http和https在处理上是不一样的。
13 | 4:封装请求,构造HttpServletRequest。把socket获取的用户请求字节流转换成java对象httprequest。构造httpResponse。
14 | 5:调用(若未创建,则先加载)servlet,调用init初始化,执行servlet.service()方法。
15 | 6:为httpResponse添加header等头部信息。
16 | 7:socket回写流,返回满足http协议格式的数据给浏览器。
17 | 8:实现JSP语法分析器,JSP标记解释器。JSP servlet实现和渲染引擎。
18 | 9:JNDI、JMX等服务实现。容器一般额外提供命名空间服务管理。
19 | 10:线程池管理,创建线程池,并为每个请求分配线程。
20 |
21 | Tomcat有自己的类加载机制。可以参考:
22 | [Java类加载原理解析](http://www.blogjava.net/zhuxing/archive/2008/08/08/220841.html)
23 | [深入探讨 Java 类加载器](http://www.ibm.com/developerworks/cn/java/j-lo-classloader/index.html)
24 | [Tomcat类加载器体系结构](http://www.cnblogs.com/ivan-zheng/articles/1789682.html)
25 |
26 |
27 | 有一本书是讲Tomcat如何运行的:[《How Tomcat Works》](http://book.douban.com/subject/1943128/)。
28 |
--------------------------------------------------------------------------------
/00-05.md:
--------------------------------------------------------------------------------
1 | 00-05、过滤器与监听器
2 | ---
3 |
4 | ## 过滤器
5 | 过滤器(Filter),并非必须,但很实用。
6 |
7 | 过滤器是一种设计模式,主要用来封装Servlet中一些通用的代码。在web.xml中配置哪些URL对应哪些过滤器。
8 |
9 | 一个过滤器的写法如下:
10 | ```java
11 | public void doFilter(ServletRequest request , ServletResponse response , FilterChain chain) {
12 | //处理 request
13 | chain.doFilter(request, response);
14 | //处理 response
15 | }
16 | ```
17 |
18 | 假设针对一URL定义了3个过滤器,分别是MyFilter1、MyFilter2、MyFilter3,在web.xml中也是按照这个顺序设置的,
19 | 那么过滤器和Servlet的执行顺序如下:
20 |
21 | * MyFilter1中处理request的代码;
22 | * MyFilter2中处理request的代码;
23 | * MyFilter3中处理request的代码;
24 | * 相应的Servlet;
25 | * MyFilter3中处理response的代码;
26 | * MyFilter2中处理response的代码;
27 | * MyFilter1中处理response的代码;
28 |
29 | 之所以能达到这样的效果,`chain.doFilter(request, response);`起到了很大的作用。
30 | 值得注意的是,如果每个Filter没有到达`chain.doFilter`就返回了,那么后续的Filter或者Servlet也就不会执行。
31 |
32 | **相关资料:**
33 | [Tomcat 的过滤诀窍](http://www.ibm.com/developerworks/cn/java/j-tomcat/)
34 | [三个有用的过滤器](http://www.iteye.com/topic/185094)
35 | [Java Web笔记 – Servlet中的Filter过滤器的介绍和使用 编写过滤器](http://www.itzhai.com/java-web-notes-servlet-filters-in-the-filter-writing-the-introduction-and-use-of-filters.html#read-more)
36 | [Intercepting HTTP Response using Servlet Filter](https://punekaramit.wordpress.com/2010/03/16/intercepting-http-response-using-servlet-filter/)
37 | [How to write response filter?](http://stackoverflow.com/questions/5634477/how-to-write-response-filter)
38 | [责任链模式](http://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html)
39 |
40 | ## 监听器
41 | 当某个事件发生时候,监听器里的方法会被调用。例如Tomcat容器启动时、销毁时,session创建时、销毁时。
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 浅入浅出Java Web
2 |
3 |
4 | ## JSP & Servlet
5 |
6 | [00-00、序](./00-00.md)
7 | [00-01、相关软件的安装](./00-01.md)
8 | [00-02、理解HTTP](./00-02.md)
9 | [00-03、从JSP开始](./00-03.md)
10 | [00-04、理解Servlet](./00-04.md)
11 | [00-05、过滤器与监听器](./00-05.md)
12 | [00-06、使用velocity模板引擎](./00-06.md)
13 | [00-07、使用数据库连接池](./00-07.md)
14 | [00-08、Tomcat的运行机制](./00-08.md)
15 |
16 | ## Spring MVC
17 |
18 | 使用Spring 4.0 。
19 |
20 | [01-00、Spring与依赖注入](./01-00.md)
21 | [01-01、Spring与面向切面编程](./01-01.md)
22 | [01-02、使用Spring MVC构建Hello World](./01-02.md)
23 | [01-03、JdbcTemplate](./01-03.md)
24 | [01-04、基于注解的URL映射](./01-04.md)
25 | [01-05、JSON](./01-05.md)
26 | [01-06、校验器](./01-06.md)
27 | [01-07、国际化](./01-07.md)
28 | [01-08、拦截器](./01-08.md)
29 | [01-09、文件上传](./01-09.md)
30 | [01-10、转换器与格式化](./01-10.md)
31 |
32 |
33 | ## Book
34 | [Spring MVC学习指南](http://book.douban.com/subject/26411275/)
35 | [JSP大学实用教程](http://book.douban.com/subject/7052099/)
36 | [Spring MVC Beginner's Guide](https://www.packtpub.com/application-development/spring-mvc-beginner%E2%80%99s-guide)
37 | [轻量级Java EE企业应用实战](http://book.douban.com/subject/10582495/)
38 |
39 | ## Online Tutorial
40 | [JSP教程 - 菜鸟教程](http://www.runoob.com/jsp/jsp-tutorial.html)
41 | [Servlet教程 - 菜鸟教程](http://www.runoob.com/servlet/servlet-tutorial.html)
42 | [Spring官方文档:Spring Framework Reference Documentation](http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/index.html)
43 | [Spring MVC官方文档:Introduction to Spring Web MVC framework](http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/mvc.html)
44 | [跟开涛学spring mvc](http://sishuok.com/forum/blogCategory/showByCategory.html?categories_id=101&user_id=2)
45 |
46 | ## Q & A
47 | [stackoverflow](http://stackoverflow.com/)
48 | [开源中国社区-问答](http://www.oschina.net/question)
49 |
50 | ## Learn More
51 | [Jetty](http://www.eclipse.org/jetty/)
52 | [Netty](http://netty.io/)
53 | [JUnit](http://junit.org/)
54 | [Maven](https://maven.apache.org/)
55 | [Gradle](http://gradle.org/)
56 | [MyBatis](http://mybatis.github.io/)
57 | [Hibernate](http://hibernate.org/)
58 | [Akka](http://akka.io/)
59 |
60 | **JUnit:**
61 | [慕课网:JUnit](http://www.imooc.com/learn/356)
62 |
63 | **Maven:**
64 | [慕课网:Maven](http://www.imooc.com/learn/443)
65 |
66 | **Gradle:**
67 | [Gradle User Guide](https://docs.gradle.org/current/userguide/userguide.html)
68 | [Gradle入门系列](http://blog.jobbole.com/71999/)
69 | [使用Gradle构建Java Web应用](http://www.blogjava.net/jiangshachina/archive/2014/01/23/409285.html)
70 | [Simple Gradle Web Application](http://codetutr.com/2013/03/23/simple-gradle-web-application/)
71 |
72 |
73 | ## Supplement
74 | [补充](./supplement.md)
75 |
--------------------------------------------------------------------------------
/supplement.md:
--------------------------------------------------------------------------------
1 | 补充
2 | ---
3 |
4 | ## 使用redis存储session
5 | [tomcat-redis-session-manager](https://github.com/jcoleman/tomcat-redis-session-manager)
6 |
7 | ## Tomcat与HTTP 1.1
8 | [Why tomcat reply HTTP 1.1 respose with an HTTP 1.0 request?](http://stackoverflow.com/questions/19461312/why-tomcat-reply-http-1-1-respose-with-an-http-1-0-request)
9 |
10 | ## 视图技术
11 | [View technologies](http://docs.spring.io/spring/docs/3.0.x/spring-framework-reference/html/view.html)
12 |
13 | ## JSTL
14 | [JSP - Standard Tag Library (JSTL) Tutorial](http://www.tutorialspoint.com/jsp/jsp_standard_tag_library.htm)
15 |
16 | ## Spring WebSocket
17 | [Using Spring 4 WebSocket, sockJS and Stomp support to implement two way server client communication](https://raymondhlee.wordpress.com/2014/01/19/using-spring-4-websocket-sockjs-and-stomp-support-to-implement-two-way-server-client-communication/)
18 | [Spring WebSocket Support](http://docs.spring.io/spring/docs/current/spring-framework-reference/html/websocket.html)
19 | [Using WebSocket to build an interactive web application](https://spring.io/guides/gs/messaging-stomp-websocket/)
20 |
21 | ## Jetty WebSocket
22 | [Jetty WebSocket Server API](http://www.eclipse.org/jetty/documentation/current/jetty-websocket-server-api.html)
23 | [Jetty 9 – Updated WebSocket API](https://webtide.com/jetty-9-updated-websocket-api/)
24 |
25 | ## Servlet、Spring异步
26 | 个人理解: 这里的异步其实就是servlet把请求交给一个线程池去处理,然后servlet线程结束。线程池慢慢地去处理这些任务。
27 | 如此,可以及时地释放servlet线程,防止线程数量太多造成性能下降。
28 | [How to use Asynchronous Servlets to improve performance](https://plumbr.eu/blog/java/how-to-use-asynchronous-servlets-to-improve-performance)
29 | [Asynchronous processing support in Servlet 3.0](http://www.javaworld.com/article/2077995/java-concurrency/asynchronous-processing-support-in-servlet-3-0.html)
30 | [Servlet 3.0 实战:异步 Servlet 与 Comet 风格应用程序](http://www.ibm.com/developerworks/cn/java/j-lo-comet/index.html)
31 | [Async Servlet Feature of Servlet 3](http://www.javacodegeeks.com/2013/08/async-servlet-feature-of-servlet-3.html)
32 |
33 | [使用spring的@Async异步执行方法](http://www.cnblogs.com/yangzhilong/p/3725071.html)
34 | [spring mvc对异步请求的处理](http://www.cnblogs.com/yangzhilong/p/3725128.html)
35 |
36 | ## 安全
37 | [jstl转义显示html标签](http://blog.csdn.net/stone5751/article/details/6579728)
38 | [XSS prevention in JSP/Servlet web application](http://stackoverflow.com/questions/2658922/xss-prevention-in-jsp-servlet-web-application)
39 | [Simple Cross Site Scripting (XSS) Servlet Filter](http://greatwebguy.com/programming/java/simple-cross-site-scripting-xss-servlet-filter/)
40 | [Spring MVC防御CSRF、XSS和SQL注入攻击](http://www.cnblogs.com/Mainz/archive/2012/11/01/2749874.html)
41 | [Spring Security 3.2.0.RC1 Highlights: CSRF Protection](http://spring.io/blog/2013/08/21/spring-security-3-2-0-rc1-highlights-csrf-protection/)
42 |
43 | ## 缓存Ehcache
44 | [Java Web Application: How to implement caching techniques?](http://stackoverflow.com/questions/699996/java-web-application-how-to-implement-caching-techniques)
45 | [Ehcache文档](http://www.ehcache.org/documentation/)
46 | [注释驱动的 Spring cache 缓存介绍](http://www.ibm.com/developerworks/cn/opensource/os-cn-spring-cache/)
47 |
48 |
49 | ## war格式
50 | [How to deploy a war file in Tomcat 7](http://stackoverflow.com/questions/5109112/how-to-deploy-a-war-file-in-tomcat-7)
51 | [如何将netbeans生成的项目文件打包发布到其他的Tomcat服务器上?](http://asdcm2008.blog.163.com/blog/static/17412758520119249517732/)
52 | [Deploying on tomcat](http://portofino.manydesigns.com/en/docs/portofino3/3_1_x/installation-guide/deploying-on-tomcat)
53 |
--------------------------------------------------------------------------------
/00-02.md:
--------------------------------------------------------------------------------
1 | 00-02、理解HTTP
2 | ---
3 |
4 | HTTP是基于TCP协议的。TCP负责数据传输,而HTTP只是规范了TCP传输的数据的格式,而这个具体的格式,请见后面给出的资料。
5 |
6 | HTTP服务的底层实现就是socket编程。
7 |
8 |
9 | 下面基于socket编写一个简单的HTTP server。
10 |
11 | ```java
12 | import java.io.BufferedReader;
13 | import java.io.BufferedWriter;
14 | import java.io.IOException;
15 | import java.io.InputStreamReader;
16 | import java.io.OutputStreamWriter;
17 | import java.io.PrintWriter;
18 | import java.net.ServerSocket;
19 | import java.net.Socket;
20 | import java.util.concurrent.Executors;
21 | import java.util.concurrent.ExecutorService;
22 |
23 | class SocketHandler implements Runnable {
24 |
25 | final static String CRLF = "\r\n"; // 1
26 |
27 | private Socket clientSocket;
28 |
29 | public SocketHandler(Socket clientSocket) {
30 | this.clientSocket = clientSocket;
31 | }
32 |
33 | public void handleSocket(Socket clientSocket) throws IOException {
34 |
35 | BufferedReader in = new BufferedReader(
36 | new InputStreamReader(clientSocket.getInputStream())
37 | );
38 | PrintWriter out = new PrintWriter(
39 | new BufferedWriter( new OutputStreamWriter(clientSocket.getOutputStream())),
40 | true
41 | );
42 |
43 | String requestHeader = "";
44 | String s;
45 | while ((s = in.readLine()) != null) {
46 | s += CRLF; // 2 很重要,默认情况下in.readLine的结果中`\r\n`被去掉了
47 | requestHeader = requestHeader + s;
48 | if (s.equals(CRLF)){ // 3 此处HTTP请求头我们都得到了;如果从请求头中判断有请求正文,则还需要继续获取数据
49 | break;
50 | }
51 | }
52 | System.out.println("客户端请求头:");
53 | System.out.println(requestHeader);
54 |
55 | String responseBody = "客户端的请求头是:\n"+requestHeader;
56 |
57 | String responseHeader = "HTTP/1.0 200 OK\r\n" +
58 | "Content-Type: text/plain; charset=UTF-8\r\n" +
59 | "Content-Length: "+responseBody.getBytes().length+"\r\n" +
60 | "\r\n";
61 | // 4 问题来了:1、浏览器如何探测编码 2、浏览器受到content-length后会按照什么方式判断?汉字的个数?字节数?
62 |
63 | System.out.println("响应头:");
64 | System.out.println(responseHeader);
65 |
66 |
67 |
68 | out.write(responseHeader);
69 | out.write(responseBody);
70 | out.flush();
71 |
72 | out.close();
73 | in.close();
74 | clientSocket.close();
75 |
76 | }
77 |
78 | @Override
79 | public void run() {
80 | try {
81 | handleSocket(clientSocket);
82 | } catch(Exception ex) {
83 | ex.printStackTrace();
84 | }
85 | }
86 |
87 | }
88 |
89 | public class MyHTTPServer {
90 |
91 | public static void main(String[] args) throws Exception {
92 |
93 | int port = 8000;
94 | ServerSocket serverSocket = new ServerSocket(port);
95 | System.out.println("启动服务,绑定端口: " + port);
96 |
97 | ExecutorService fixedThreadPool = Executors.newFixedThreadPool(30); // 5
98 |
99 | while (true) { // 6
100 | Socket clientSocket = serverSocket.accept();
101 | System.out.println("新的连接"
102 | + clientSocket.getInetAddress() + ":" + clientSocket.getPort());
103 | try {
104 | fixedThreadPool.execute(new SocketHandler(clientSocket));
105 | } catch (Exception e) {
106 | System.out.println(e);
107 | }
108 | }
109 | }
110 | }
111 | ```
112 |
113 | 这是一个实现HTTP 1.0的服务器,对于所有的HTTP请求,会把HTTP请求头响应回去。
114 | 这个程序说明了web服务器处理请求的基本流程,JSP、Servlet、Spring MVC等只是在
115 | 这个基础上嫁了许多方法,以让我们更方面的编写web应用。web服务器不仅可以基于多线程,
116 | 也可以基于多进程、Reactor模型等。
117 |
118 | **测试程序:**
119 | 运行上面的程序。我们使用curl访问`http://127.0.0.1`(也可以使用浏览器):
120 | ```shell
121 | $ curl -i http://127.0.0.1:8000
122 | HTTP/1.0 200 OK
123 | Content-Type: text/plain; charset=UTF-8
124 | Content-Length: 106
125 |
126 | 客户端的请求头是:
127 | GET / HTTP/1.1
128 | User-Agent: curl/7.35.0
129 | Host: 127.0.0.1:8000
130 | Accept: */*
131 | ```
132 |
133 | Java程序输出:
134 | ```shell
135 | 启动服务,绑定端口: 8000
136 | 新的连接/127.0.0.1:36463
137 | 新的连接/127.0.0.1:36463客户端请求头:
138 | GET / HTTP/1.1
139 | User-Agent: curl/7.35.0
140 | Host: 127.0.0.1:8000
141 | Accept: */*
142 |
143 |
144 | 响应头:
145 | HTTP/1.0 200 OK
146 | Content-Type: text/plain; charset=UTF-8
147 | Content-Length: 106
148 | ```
149 |
150 | **程序解析:**
151 |
152 | `// 1`:定义了HTTP头的换行符。
153 |
154 | `// 2`:in.readLine()的结果默认不带换行符,这里把它加上。(这不是强制的,主要看你的程序逻辑需不需要,
155 | 这个程序的目标是把HTTP请求头响应回去)。
156 |
157 | `// 3`:此时s是一个空行,根据HTTP协议,整个请求头都得到了。
158 |
159 | `// 4`:Content-Length的值是字节的数量。
160 |
161 | `// 5`:线程池。
162 |
163 | `// 6`:这个循环不停监听socket连接,使用SocketHandler处理连入的socket,而这个处理是放在线程池中的。
164 |
165 | **HTTP 1.1:**
166 | HTTP 1.1也是在这个思路的基础上实现的,即多个HTTP请求都在一个TCP连接中传输。对于HTTP 1.1,如何区分出每个HTTP请求很重要,
167 | 比较简单的可以是用过`Content-Length`判断一条请求是否结束。如果一个HTTP请求数据较多,往往采用Chunked方式,
168 | 可以参考[Chunked transfer encoding](https://en.wikipedia.org/wiki/Chunked_transfer_encoding)。
169 |
170 |
171 | ## HTTP相关资料
172 |
173 | **网络教程:**
174 | [菜鸟教程-HTTP教程](http://www.runoob.com/http/http-tutorial.html)
175 | [List of HTTP header fields](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields)
176 | [14 Header Field Definitions](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html)
177 | [HTTP header should use what character encoding?](http://stackoverflow.com/questions/4400678/http-header-should-use-what-character-encoding)
178 |
179 |
180 | **书籍:**
181 | [HTTP权威指南]()
182 | [计算机网络]() 谢希仁
183 |
--------------------------------------------------------------------------------
/01-07.md:
--------------------------------------------------------------------------------
1 | 01-07、国际化
2 | ---
3 |
4 | 本节的项目以为[01-06、校验器](./01-06.md)创建的项目`Project_0106`为基础。
5 |
6 | 所谓国际化,是指根据浏览器HTTP请求头中`Accept-Language`中指定的语言、或者用户指定的语言(Cookie、session中指定),
7 | 将web页面中的一些文本使用该语言展示出来。
8 |
9 | ## 根据浏览器HTTP请求头中`Accept-Language`指定的语言进行国际化
10 |
11 | 项目结构如下:
12 | 
13 |
14 | ### 源码
15 | 这里只展示改动或者新增的文件。
16 |
17 | **dispatcher-servlet.xml**
18 | ```xml
19 |
20 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | indexController
42 |
43 |
44 |
45 |
46 |
50 |
51 |
54 |
55 |
56 |
57 |
58 |
59 | /WEB-INF/resource/message00
60 | /WEB-INF/resource/message01
61 |
62 |
63 |
64 |
65 |
68 |
69 | ```
70 |
71 | **message00.properties**
72 | ```plain
73 | welcome=hello
74 | person.firstName.notempty=firstName can not be empty
75 | person.secondName.notempty=secondName can not be empty
76 | person.firstName.tooshort=firstName is too short
77 | ```
78 |
79 | **message00_en_US.properties**
80 | ```plain
81 | welcome=hello
82 | person.firstName.notempty=firstName can not be empty
83 | person.secondName.notempty=secondName can not be empty
84 | person.firstName.tooshort=firstName is too short
85 | ```
86 | **message00_zh_CN.properties**
87 | ```plain
88 | welcome=你好
89 | person.firstName.notempty=firstName不能为空
90 | person.secondName.notempty=secondName不能为空
91 | person.firstName.tooshort=firstName太短
92 | ```
93 | **message01\*.properties**
94 | 这三个文件为空。
95 |
96 | **PersonValidator.java**
97 | ```java
98 | package me.letiantian.validator;
99 |
100 | import me.letiantian.form.Person;
101 | import org.springframework.validation.Errors;
102 | import org.springframework.validation.Validator;
103 | import org.springframework.validation.ValidationUtils;
104 |
105 | public class PersonValidator implements Validator{
106 |
107 | @Override
108 | public boolean supports(Class> type) {
109 | return Person.class.isAssignableFrom(type);
110 | }
111 |
112 | @Override
113 | public void validate(Object o, Errors errors) {
114 | Person person = (Person) o;
115 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", "person.firstName.notempty");
116 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "secondName", "person.secondName.notempty");
117 | if (person.getFirstName().length() < 2) {
118 | errors.rejectValue("firstName", "person.firstName.tooshort");
119 | }
120 | }
121 |
122 | }
123 | ```
124 | **hello/input.jsp**
125 | ```html
126 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
127 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
128 | <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
129 | <%@taglib prefix="spring" uri="http://www.springframework.org/tags"%>
130 |
131 |
132 |
133 |
134 | JSP Page
135 |
138 |
139 |
140 |
141 |
142 | firstName:
143 | secondName:
144 |
145 |
146 |
147 |
148 |
149 | ```
150 |
151 | ### 效果
152 | 可以参考[Change Mozilla Firefox language settings](http://pchelp.ricmedia.com/change-mozilla-firefox-language-settings/)修改火狐浏览器的Accept-Language。
153 | 如果没有效果,可以使用netbeans重启项目,再查看效果。
154 |
155 | 
156 |
157 | 
158 |
159 | ## 其他方式的国际化
160 |
161 | 上面的程序中`localeResolver`使用的`AcceptHeaderLocaleResolver`(见配置文件`dispatcher-servlet.xml`)。
162 | 另外,Spring还给出`SessionLocaleResolver`、`CookieLocaleResolver`来实现国际化。也可以根据URL中的指定的Locale进行国际化。
163 |
164 | 可以参考:
165 | [SpringMVC学习系列(8) 之 国际化](http://www.cnblogs.com/liukemng/p/3750117.html)
166 | [Spring MVC internationalization example](http://www.mkyong.com/spring-mvc/spring-mvc-internationalization-example)
167 |
--------------------------------------------------------------------------------
/00-06.md:
--------------------------------------------------------------------------------
1 | 00-06、使用velocity模板引擎
2 | ---
3 |
4 | > Velocity is a Java-based template engine. It permits anyone to use a simple yet powerful template language to reference objects defined in Java code.
5 |
6 | > When Velocity is used for web development, Web designers can work in parallel with Java programmers to develop web sites according to the Model-View-Controller (MVC) model, meaning that web page designers can focus solely on creating a site that looks good, and programmers can focus solely on writing top-notch code. Velocity separates Java code from the web pages, making the web site more maintainable over its lifespan and providing a viable alternative to Java Server Pages (JSPs) or PHP.
7 |
8 | 以上内容摘自[velocity的官方首页](http://velocity.apache.org/engine/devel/)。
9 |
10 | 以下通过示例来说明velocity的使用。
11 |
12 | ## 项目结构
13 | 在[http://velocity.apache.org/download.cgi](http://velocity.apache.org/download.cgi)中下载velocity-1.7、velocity-tools-2.0。
14 |
15 | 参考[00-03、从JSP开始](./00-03.md)所述,创建项目`Project_0006_Velocity`,导入相关的jar,编写代码。
16 |
17 | 项目结构如下:
18 | 
19 |
20 | 对于新增的jar,放到/WEB-INF/lib目录即可。但当多个webApp要使用时,放入CLASSPATH或Servlet容器(如Tomcat)的顶层lib是最好的选择.
21 |
22 | ## 代码
23 | web.xml(在这一节,该文件可以忽略):
24 | ```xml
25 |
26 |
27 |
28 |
29 | default
30 | *.jpg
31 |
32 |
33 |
34 | default
35 | *.png
36 |
37 |
38 |
39 | default
40 | *.js
41 |
42 |
43 |
44 | default
45 | *.css
46 |
47 |
48 |
49 |
50 | 30
51 |
52 |
53 |
54 |
55 | ```
56 |
57 | hello.vm:
58 | ```html
59 |
60 |
61 |
62 |
63 |
64 | #set( $this = "Velocity")
65 | $this is great!
66 | $name
67 | hi , i am letian
68 | 你好
69 |
70 |
71 | ```
72 |
73 | HelloServlet.java:
74 | ```java
75 | package me.letiantian.servlet;
76 |
77 | import java.io.IOException;
78 | import java.io.PrintWriter;
79 | import javax.servlet.ServletException;
80 | import javax.servlet.annotation.WebServlet;
81 | import javax.servlet.http.HttpServlet;
82 | import javax.servlet.http.HttpServletRequest;
83 | import javax.servlet.http.HttpServletResponse;
84 |
85 | import java.util.Properties;
86 | import java.io.StringWriter;
87 | import org.apache.velocity.app.Velocity;
88 | import org.apache.velocity.app.VelocityEngine;
89 | import org.apache.velocity.VelocityContext;
90 |
91 |
92 | @WebServlet(name = "HelloServlet", urlPatterns = {"/hello"})
93 | public class HelloServlet extends HttpServlet {
94 |
95 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
96 | throws ServletException, IOException {
97 | response.setContentType("text/html;charset=UTF-8");
98 | PrintWriter out = response.getWriter();
99 |
100 | Properties properties=new Properties();
101 | properties.setProperty("resource.loader", "webapp");
102 | properties.setProperty("webapp.resource.loader.class", "org.apache.velocity.tools.view.servlet.WebappLoader");
103 | properties.setProperty("webapp.resource.loader.path", "/WEB-INF/template");
104 | properties.setProperty(Velocity.ENCODING_DEFAULT, "UTF-8");
105 | properties.setProperty(Velocity.INPUT_ENCODING, "UTF-8");
106 | properties.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8");
107 | VelocityEngine velocityEngine = new VelocityEngine(properties);
108 | velocityEngine.setApplicationAttribute("javax.servlet.ServletContext", request.getServletContext());
109 |
110 | VelocityContext context=new VelocityContext();
111 | context.put("name", "user01");
112 | StringWriter sw = new StringWriter();
113 | velocityEngine.mergeTemplate("hello.vm", "utf-8", context, sw);
114 | // velocityEngine.mergeTemplate("hello.vm", "utf-8", context, sw); //如果这行不注释,hello.vm的内容会出现两次
115 | out.println(sw.toString());
116 |
117 | }
118 |
119 | @Override
120 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
121 | throws ServletException, IOException {
122 | processRequest(request, response);
123 | }
124 |
125 | @Override
126 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
127 | throws ServletException, IOException {
128 | processRequest(request, response);
129 | }
130 |
131 | }
132 | ```
133 |
134 | 运行项目,用浏览器访问`http://127.0.0.1:8084/Project_0006_Velocity/hello`:
135 | 
136 |
137 |
138 | ## 改进上面的代码
139 |
140 | 在WEB-INF目录下创建`velocity.properties`文件,其内容如下:
141 | ```plain
142 | resource.loader=webapp
143 | webapp.resource.loader.class=org.apache.velocity.tools.view.servlet.WebappLoader
144 | webapp.resource.loader.path=/WEB-INF/template/
145 | input.encoding=utf-8
146 | output.encoding=utf-8
147 | ```
148 |
149 | 修改HelloServlet.java:
150 | ```java
151 | package me.letiantian.servlet;
152 |
153 | import java.io.IOException;
154 | import java.io.PrintWriter;
155 | import javax.servlet.ServletException;
156 | import javax.servlet.annotation.WebServlet;
157 | import javax.servlet.http.HttpServlet;
158 | import javax.servlet.http.HttpServletRequest;
159 | import javax.servlet.http.HttpServletResponse;
160 |
161 | import java.util.Properties;
162 | import java.io.StringWriter;
163 | import org.apache.velocity.app.VelocityEngine;
164 | import org.apache.velocity.VelocityContext;
165 |
166 |
167 | @WebServlet(name = "HelloServlet", urlPatterns = {"/hello"})
168 | public class HelloServlet extends HttpServlet {
169 |
170 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
171 | throws ServletException, IOException {
172 | response.setContentType("text/html;charset=UTF-8");
173 | PrintWriter out = response.getWriter();
174 |
175 | Properties properties=new Properties();
176 | properties.load(getServletContext().getResourceAsStream("/WEB-INF/velocity.properties"));
177 |
178 | VelocityEngine velocityEngine = new VelocityEngine(properties);
179 | velocityEngine.setApplicationAttribute("javax.servlet.ServletContext", request.getServletContext());
180 |
181 | VelocityContext context=new VelocityContext();
182 | context.put("name", "user01");
183 | StringWriter sw = new StringWriter();
184 | velocityEngine.mergeTemplate("hello.vm", "utf-8", context, sw);
185 |
186 | out.println(sw.toString());
187 |
188 | }
189 |
190 | @Override
191 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
192 | throws ServletException, IOException {
193 | processRequest(request, response);
194 | }
195 |
196 | @Override
197 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
198 | throws ServletException, IOException {
199 | processRequest(request, response);
200 | }
201 |
202 | }
203 | ```
204 |
205 | ## 资料
206 |
207 | [velocity模板加载](http://www.blogjava.net/sxyx2008/archive/2010/11/11/337799.html)
208 | [velocity整合servlet](http://www.blogjava.net/sxyx2008/archive/2010/11/11/337819.html)
209 | [Velocity三——基于Servlet+Velocity的web应用](http://bit1129.iteye.com/blog/2106142)
210 | [使用 Velocity 实现客户端和服务器端模板](http://www.ibm.com/developerworks/cn/java/j-velocity/)
211 | [Servlet 知识详解(一)之 —— ServletContext对象 和 ServletConfig对象 学习笔记](http://even2012.iteye.com/blog/1838063)
212 |
--------------------------------------------------------------------------------
/00-03.md:
--------------------------------------------------------------------------------
1 | 00-03、从JSP开始
2 | ---
3 |
4 | ## 创建web项目
5 | 打开netbeans,在菜单栏依次选择“File”、“New Project...”,然后
6 |
7 | 1、选择java web:
8 | 
9 |
10 | 2、项目名称、路径:
11 | 
12 |
13 | 3、选择使用的web容器,编写ContextPath:
14 | 
15 |
16 | 生成的web项目结构如下:
17 | 
18 |
19 | index.html的内容如下:
20 | ```html
21 |
22 |
27 |
28 |
29 | TODO supply a title
30 |
31 |
32 |
33 |
34 | TODO write content
35 |
36 |
37 | ```
38 |
39 | `context.xml`的内容如下:
40 | ```xml
41 |
42 |
43 | ```
44 |
45 | `apache-tomcat-8.0.15/conf/server.xml`中关于端口的配置如下:
46 | ```xml
47 |
50 | ```
51 |
52 | 运行项目后,netbeans的输出信息如下:
53 | ```
54 | ant -f /data/Code/netbeans/HelloJSP -Dnb.internal.action.name=run -Ddirectory.deployment.supported=true -DforceRedeploy=false -Dnb.wait.for.caches=true -Dbrowser.context=/data/Code/netbeans/HelloJSP run
55 | init:
56 | deps-module-jar:
57 | deps-ear-jar:
58 | deps-jar:
59 | library-inclusion-in-archive:
60 | library-inclusion-in-manifest:
61 | compile:
62 | compile-jsps:
63 | Incrementally deploying http://localhost:8084/HelloJSP
64 | Completed incremental distribution of http://localhost:8084/HelloJSP
65 | run-deploy:
66 | Browsing: http://localhost:8084/HelloJSP
67 | run-display-browser:
68 | run:
69 | ```
70 |
71 | 使用浏览器访问`http://localhost:8084/HelloJSP/`,能看到`TODO write content`。
72 |
73 | **那么问题来了,为什么配置的是8080,访问时却用8084端口?**
74 | 答案是:这个端口是netbeans启动tomcat时配置的。
75 |
76 | 看一下启动命令:
77 | ```shell
78 | $ ps -ef | grep 'tomcat' | grep -v grep
79 | letian 390 24314 0 09:24 ? 00:00:08 /data/Apps/jdk1.8.0_20/bin/java -Djava.util.logging.config.file=/home/letian/.netbeans/8.0.2/apache-tomcat-8.0.15.0_base/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dhttp.nonProxyHosts=localhost|127.0.0.1|myhost -Djava.endorsed.dirs=/data/Apps/apache-tomcat-8.0.15/endorsed -classpath /data/Apps/apache-tomcat-8.0.15/bin/bootstrap.jar:/data/Apps/apache-tomcat-8.0.15/bin/tomcat-juli.jar -Dcatalina.base=/home/letian/.netbeans/8.0.2/apache-tomcat-8.0.15.0_base -Dcatalina.home=/data/Apps/apache-tomcat-8.0.15 -Djava.io.tmpdir=/home/letian/.netbeans/8.0.2/apache-tomcat-8.0.15.0_base/temp org.apache.catalina.startup.Bootstrap start
80 |
81 | $ grep -r '8084' /home/letian/.netbeans/8.0.2 # 可以看到很多结果
82 | ...
83 | ```
84 |
85 | 也就是说,实际使用的是`/home/letian/.netbeans/8.0.2/apache-tomcat-8.0.15.0_base/conf`
86 | 下的配置。在``/home/letian/.netbeans/8.0.2/apache-tomcat-8.0.15.0_base/conf/Catalina/localhost/HelloJSP.xml`中有以下内容:
87 | ```xml
88 |
89 | ```
90 | 这意味着访问`http://localhost:8084/HelloJSP/`时对应的web应用部署在HelloJSP项目
91 | 的`build/web/`目录下。
92 |
93 |
94 | ## 基于JSP的hello world
95 | 删除index.html,新建index.jsp,内容如下:
96 | ```html
97 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
98 |
99 |
100 |
101 |
102 | JSP Page
103 |
104 |
105 | <%
106 | String data="hello world";
107 | boolean flag=true;
108 | if (flag==true) {
109 | out.println("" +data.toUpperCase()+ " ");
110 | }
111 | %>
112 |
113 |
114 | ```
115 | 运行项目,访问`http://localhost:8084/HelloJSP/`,可以看到`HELLO WORLD`。
116 |
117 | JSP在部署时会被转换成servlet,`/home/letian/.netbeans/8.0.2/apache-tomcat-8.0.15.0_base/work/Catalina/localhost/HelloJSP/org/apache/jsp`中的`index_jsp.java`就是对应的servlet。其内容如下:
118 | ```java
119 | /*
120 | * Generated by the Jasper component of Apache Tomcat
121 | * Version: Apache Tomcat/8.0.15
122 | * Generated at: 2015-09-18 02:43:43 UTC
123 | * Note: The last modified time of this file was set to
124 | * the last modified time of the source file after
125 | * generation to assist with modification tracking.
126 | */
127 | package org.apache.jsp;
128 |
129 | import javax.servlet.*;
130 | import javax.servlet.http.*;
131 | import javax.servlet.jsp.*;
132 |
133 | public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
134 | implements org.apache.jasper.runtime.JspSourceDependent {
135 |
136 | private static final javax.servlet.jsp.JspFactory _jspxFactory =
137 | javax.servlet.jsp.JspFactory.getDefaultFactory();
138 |
139 | private static java.util.Map _jspx_dependants;
140 |
141 | private javax.el.ExpressionFactory _el_expressionfactory;
142 | private org.apache.tomcat.InstanceManager _jsp_instancemanager;
143 |
144 | public java.util.Map getDependants() {
145 | return _jspx_dependants;
146 | }
147 |
148 | public void _jspInit() {
149 | _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
150 | _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
151 | }
152 |
153 | public void _jspDestroy() {
154 | }
155 |
156 | public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
157 | throws java.io.IOException, javax.servlet.ServletException {
158 |
159 | final java.lang.String _jspx_method = request.getMethod();
160 | if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
161 | response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET POST or HEAD");
162 | return;
163 | }
164 |
165 | final javax.servlet.jsp.PageContext pageContext;
166 | javax.servlet.http.HttpSession session = null;
167 | final javax.servlet.ServletContext application;
168 | final javax.servlet.ServletConfig config;
169 | javax.servlet.jsp.JspWriter out = null;
170 | final java.lang.Object page = this;
171 | javax.servlet.jsp.JspWriter _jspx_out = null;
172 | javax.servlet.jsp.PageContext _jspx_page_context = null;
173 |
174 |
175 | try {
176 | response.setContentType("text/html;charset=UTF-8");
177 | pageContext = _jspxFactory.getPageContext(this, request, response,
178 | null, true, 8192, true);
179 | _jspx_page_context = pageContext;
180 | application = pageContext.getServletContext();
181 | config = pageContext.getServletConfig();
182 | session = pageContext.getSession();
183 | out = pageContext.getOut();
184 | _jspx_out = out;
185 |
186 | out.write("\n");
187 | out.write("\n");
188 | out.write("\n");
189 | out.write(" \n");
190 | out.write(" \n");
191 | out.write(" JSP Page \n");
192 | out.write(" \n");
193 | out.write(" \n");
194 | out.write(" ");
195 |
196 | String data="hello world";
197 | boolean flag=true;
198 | if (flag==true) {
199 | out.println("" +data.toUpperCase()+ " ");
200 | }
201 |
202 | out.write("\n");
203 | out.write(" \n");
204 | out.write("\n");
205 | } catch (java.lang.Throwable t) {
206 | if (!(t instanceof javax.servlet.jsp.SkipPageException)){
207 | out = _jspx_out;
208 | if (out != null && out.getBufferSize() != 0)
209 | try {
210 | if (response.isCommitted()) {
211 | out.flush();
212 | } else {
213 | out.clearBuffer();
214 | }
215 | } catch (java.io.IOException e) {}
216 | if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
217 | else throw new ServletException(t);
218 | }
219 | } finally {
220 | _jspxFactory.releasePageContext(_jspx_page_context);
221 | }
222 | }
223 | }
224 | ```
225 | 感受一下这段代码吧~
226 |
227 | 关于JSP就介绍这么多。**需要记住的是:JSP最合适的用途是用作MVC中的视图,而不是和HTML一起混合编码
228 | (例如把从数据库拉取数据也放入JSP中写)**
229 |
230 | 要了解更多,请参考下面的相关资料。
231 |
232 | ## JSP相关资料
233 | [JSP 教程](http://www.runoob.com/jsp/jsp-tutorial.html)
234 |
--------------------------------------------------------------------------------
/01-09.md:
--------------------------------------------------------------------------------
1 | 01-09、文件上传
2 | ---
3 |
4 | 先看一下Servlet是如何处理文件上传的:
5 | [Servlets - File Uploading](http://www.tutorialspoint.com/servlets/servlets-file-uploading.htm)
6 | [Java File Upload Example with Servlet 3.0 API](http://www.codejava.net/java-ee/servlet/java-file-upload-example-with-servlet-30-api)
7 |
8 | Spring MVC下的处理是类似的。
9 |
10 | 下面展示一个简单的实现。
11 |
12 | ## 项目结构与源码
13 | 
14 |
15 | ### web.xml
16 | ```xml
17 |
18 |
19 |
20 | contextConfigLocation
21 | /WEB-INF/applicationContext.xml
22 |
23 |
24 | org.springframework.web.context.ContextLoaderListener
25 |
26 |
27 | dispatcher
28 | org.springframework.web.servlet.DispatcherServlet
29 | 2
30 |
31 | 1000000
32 | 2000000
33 | 4000000
34 |
35 |
36 |
37 | dispatcher
38 | /
39 |
40 |
41 |
42 | 30
43 |
44 |
45 |
46 | redirect.jsp
47 |
48 |
49 | ```
50 |
51 | 注意其中的限制文件大小的配置:
52 | ```xml
53 |
54 | 1000000
55 | 2000000
56 | 4000000
57 |
58 | ```
59 |
60 | ### applicationContext.xml
61 | ```xml
62 |
63 |
64 |
72 |
73 |
74 | ```
75 |
76 | ### dispatcher-servlet.xml
77 | ```xml
78 |
79 |
91 |
92 |
93 |
94 |
95 |
96 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | indexController
106 |
107 |
108 |
109 |
110 |
114 |
115 |
118 |
119 |
120 |
121 |
122 | ```
123 |
124 | 注意,这里增加了一个multipart解析器`StandardServletMultipartResolver`,用来处理上传的文件。`/static`是存放静态资源的目录,
125 | 我们也准备将上传的文件放到这个目录里。
126 |
127 | ### UploadedFile.java
128 | ```java
129 | package me.letiantian.form;
130 |
131 | import org.springframework.web.multipart.MultipartFile;
132 |
133 | public class UploadedFile {
134 | private String fileName;
135 | private MultipartFile multipartFile;
136 |
137 | public String getFileName() {
138 | return fileName;
139 | }
140 |
141 | public void setFileName(String fileName) {
142 | this.fileName = fileName;
143 | }
144 |
145 | public MultipartFile getMultipartFile() {
146 | return multipartFile;
147 | }
148 |
149 | public void setMultipartFile(MultipartFile multipartFile) {
150 | this.multipartFile = multipartFile;
151 | }
152 |
153 | }
154 | ```
155 |
156 | ### HelloController.java
157 |
158 | ```java
159 | package me.letiantian.controller;
160 |
161 | import java.io.File;
162 | import java.io.IOException;
163 | import java.io.PrintWriter;
164 | import javax.servlet.http.HttpServletRequest;
165 | import javax.servlet.http.HttpServletResponse;
166 | import org.springframework.stereotype.Controller;
167 | import org.springframework.web.bind.annotation.RequestMapping;
168 | import me.letiantian.form.UploadedFile;
169 | import org.springframework.web.bind.annotation.ModelAttribute;
170 |
171 | import org.springframework.web.multipart.MultipartFile;
172 |
173 | @Controller
174 | @RequestMapping("/hello")
175 | public class HelloController{
176 |
177 |
178 | @RequestMapping(value = "")
179 | public String index() {
180 | return "hello/index";
181 | }
182 |
183 | @RequestMapping(value = "/upload")
184 | public void output(@ModelAttribute UploadedFile uploadedFile,
185 | HttpServletRequest request,
186 | HttpServletResponse response) throws IOException {
187 | response.setContentType("text/html;charset=UTF-8");
188 | PrintWriter out = response.getWriter();
189 | MultipartFile multiPartFile = uploadedFile.getMultipartFile();
190 | System.out.println("文件原始名称:"+multiPartFile.getOriginalFilename());
191 | System.out.println("表单给定的文件名称:"+uploadedFile.getFileName());
192 |
193 | try{
194 | System.out.println("上传目录:"+request.getServletContext().getRealPath("/static"));
195 | File file = new File(request.getServletContext().getRealPath("/static"),
196 | uploadedFile.getFileName());
197 | multiPartFile.transferTo(file); // 将文件写入本地
198 | out.println("上传成功 ");
199 | } catch (Exception ex) {
200 | System.out.println(""+ex.getMessage());
201 | out.println("上传失败 ");
202 | }
203 | }
204 |
205 | }
206 | ```
207 | 注意,表单数据被绑定到了`uploadedFile`对象中。
208 |
209 | ### hello/index.jsp
210 | ```html
211 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
212 |
213 |
214 |
215 |
216 | JSP Page
217 |
218 |
219 |
224 |
225 |
226 | ```
227 |
228 | ## 测试程序
229 | 选择文件,指定名称:
230 | 
231 |
232 | 上传成功:
233 | 
234 |
235 | 查看上传的文件:
236 | 
237 |
238 | Tomcat输出:
239 | ```plain
240 | 文件原始名称:01.png
241 | 表单给定的文件名称:1.png
242 | 上传目录:/data/Code/netbeans/Project_0109/build/web/static
243 | ```
244 |
245 | ## 资料
246 | 《Spring MVC学习指南》 第11章
247 |
--------------------------------------------------------------------------------
/01-04.md:
--------------------------------------------------------------------------------
1 | 01-04、基于注解的URL映射
2 | ---
3 |
4 |
5 | ## 项目结构
6 | 创建项目`Pcrojet_0104`,最终结构如下:
7 | 
8 |
9 | ## 源码
10 |
11 | ### applicationContext.xml
12 | ```xml
13 |
14 |
27 |
28 |
29 | ```
30 | 该配置文件什么都没做。
31 |
32 | ### dispatcher-servlet.xml
33 | ```xml
34 |
35 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | indexController
57 |
58 |
59 |
60 |
61 |
65 |
66 |
69 |
70 |
71 | ```
72 |
73 | ``中增加了属性`xmlns:context`、`xmlns:mvc`,对应的在`xsi:schemaLocation`增加了:
74 | ```plain
75 | http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
76 | http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
77 | ```
78 |
79 | 关于` `的意义,可参考[What's the difference between and in servlet?](http://stackoverflow.com/questions/3977973/whats-the-difference-between-mvcannotation-driven-and-contextannotation)。
80 |
81 | ### web.xml
82 | ```xml
83 |
84 |
85 |
86 | contextConfigLocation
87 | /WEB-INF/applicationContext.xml
88 |
89 |
90 | org.springframework.web.context.ContextLoaderListener
91 |
92 |
93 | dispatcher
94 | org.springframework.web.servlet.DispatcherServlet
95 | 2
96 |
97 |
98 | dispatcher
99 | /
100 |
101 |
102 |
103 | 30
104 |
105 |
106 |
107 | redirect.jsp
108 |
109 |
110 | ```
111 |
112 | ### 模板文件
113 |
114 | **index.jsp:**
115 | ```html
116 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
117 |
119 |
120 |
121 |
122 |
123 | Welcome to Spring Web MVC project
124 |
125 |
126 |
127 | Hello! This is the default welcome page for a Spring Web MVC project.
128 | To display a different welcome page for this project, modify
129 | index.jsp , or create your own welcome page then change
130 | the redirection in redirect.jsp to point to the new
131 | welcome page and also update the welcome-file setting in
132 | web.xml .
133 |
134 |
135 | ```
136 |
137 | **hello/method01.jsp:**
138 | ```html
139 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
140 |
141 |
142 |
143 |
144 | JSP Page
145 |
146 |
147 | Hello Method01
148 |
149 |
150 | ```
151 |
152 | **hello/method04.jsp:**
153 | ```plain
154 | <%@page contentType="text/plain" pageEncoding="UTF-8"%>
155 |
156 | name: ${name}
157 | ```
158 |
159 | ### HelloController.java
160 | ```java
161 | package me.letiantian.controller;
162 |
163 | import java.io.PrintWriter;
164 | import javax.servlet.http.HttpServletRequest;
165 | import javax.servlet.http.HttpServletResponse;
166 | import org.springframework.stereotype.Controller;
167 | import org.springframework.ui.Model;
168 | import org.springframework.web.bind.annotation.PathVariable;
169 | import org.springframework.web.bind.annotation.RequestMapping;
170 | import org.springframework.web.bind.annotation.RequestMethod;
171 |
172 | @Controller
173 | @RequestMapping("/hello")
174 | public class HelloController{
175 |
176 | @RequestMapping(value = "")
177 | public String index() {
178 | return "index";
179 | }
180 |
181 | @RequestMapping(value = "/method01")
182 | public String method01() {
183 | return "hello/method01";
184 | }
185 |
186 | // 仅支持HTTP POST方法
187 | @RequestMapping(value = "/method02", method = {RequestMethod.POST})
188 | public String method02() {
189 | return "hello/method01";
190 | }
191 |
192 | @RequestMapping(value = "/method03")
193 | public void method03(HttpServletRequest request, HttpServletResponse response) {
194 | response.setContentType("text/plain;charset=UTF-8");
195 | try (PrintWriter out = response.getWriter()) {
196 | out.println("contextPath: " + request.getContextPath());
197 | out.println("name: " + request.getParameter("name"));
198 | } catch (Exception ex) {
199 | System.out.println(""+ex.getMessage());
200 | }
201 | }
202 |
203 | @RequestMapping(value = "/method04/{name}")
204 | public String method04(@PathVariable String name, Model model) {
205 | model.addAttribute("name", name);
206 | return "hello/method04";
207 | }
208 |
209 | @RequestMapping(value = "/method05/{id}")
210 | public String method05(@PathVariable int id, Model model) {
211 | model.addAttribute("name", id);
212 | return "hello/method04";
213 | }
214 | }
215 | ```
216 |
217 | ## 测试
218 |
219 | 
220 | 
221 | 
222 | 
223 | 
224 | 
225 | 
226 | 
227 |
228 | ## 其他
229 |
230 | **如何让一个方法映射多个URL?**
231 | 很简单,例如`@RequestMapping(value = {"/hello", "/hi"})`。可参考[Spring MVC: Mapping Multiple URLs to Same Controller](http://stackoverflow.com/questions/3898442/spring-mvc-mapping-multiple-urls-to-same-controller)。
232 |
233 | **如何自定义错误页面?**
234 | [Spring MVC : How To Return Custom 404 Error Pages](http://www.javabeat.net/spring-mvc-404-error-page/)
235 | [Spring MVC Exception Handling Example](http://www.mkyong.com/spring-mvc/spring-mvc-exception-handling-example/)
236 | [Exception Handling in Spring MVC](https://spring.io/blog/2013/11/01/exception-handling-in-spring-mvc)
237 |
238 | **@PathVariable是绑定数据的其中一种方法,还有绑定Cookie中数据,将表单数据绑定到对象中等方法:**
239 | [Spring MVC Cookie example](http://viralpatel.net/blogs/spring-mvc-cookie-example/)
240 | [Injecting and Binding Objects to Spring MVC Controllers](http://www.cnblogs.com/davidwang456/p/4019595.html)
241 |
--------------------------------------------------------------------------------
/00-07.md:
--------------------------------------------------------------------------------
1 | 00-07、使用数据库连接池
2 | ---
3 |
4 | 目前比较常见的连接池实现有DBCP、C3P0,Tomcat_JDBC等。
5 |
6 | 本文使用的连接池是DBCP。
7 |
8 | 进入[http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi](http://commons.apache.org/proper/commons-dbcp/download_dbcp.cgi)下载`Apache Commons DBCP for JDBC `,[http://commons.apache.org/proper/commons-pool/download_pool.cgi](http://commons.apache.org/proper/commons-pool/download_pool.cgi)中下载`Apache Commons Pool`,[http://dev.mysql.com/downloads/connector/j/](http://dev.mysql.com/downloads/connector/j/)下载MySQL的JDBC驱动。
9 |
10 | 若下载出现问题,可以到一些Maven仓库中下载。例如[http://mvnrepository.com/](http://mvnrepository.com/)、[http://maven.oschina.net](http://maven.oschina.net)。
11 |
12 |
13 | ## 数据库准备
14 | MySQL 5.6。
15 |
16 | ```sql
17 | --创建数据库
18 | CREATE DATABASE IF NOT EXISTS `test` DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
19 | USE `test`;
20 | --创建table
21 | CREATE TABLE IF NOT EXISTS user
22 | (
23 | `id` int AUTO_INCREMENT,
24 | `name` varchar(255),
25 | `email` varchar(255),
26 | `age` varchar(255),
27 | `passwd` varchar(255),
28 | PRIMARY KEY (`id`),
29 | UNIQUE KEY (`name`),
30 | UNIQUE KEY (`email`)
31 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
32 | ---插入若干数据
33 | INSERT INTO user (`name`, `email`, `age`, `passwd`)
34 | VALUES ('user01', 'user01@163.com', 20, password('123'));
35 |
36 | INSERT INTO user (`name`, `email`, `age`, `passwd`)
37 | VALUES ('user02', 'user02@163.com', 20, password('456'));
38 | ```
39 |
40 | ## 示例1
41 |
42 | 目录结构如下:
43 | 
44 |
45 | **web.xml源码:**
46 | ```xml
47 |
48 |
49 |
50 |
51 | default
52 | *.jpg
53 |
54 |
55 |
56 | default
57 | *.png
58 |
59 |
60 |
61 | default
62 | *.js
63 |
64 |
65 |
66 | default
67 | *.css
68 |
69 |
70 |
71 |
72 | 30
73 |
74 |
75 |
76 |
77 | ```
78 |
79 | **dbcp.properties源码:**
80 | ```plain
81 | driverClassName=com.mysql.jdbc.Driver
82 | url=jdbc:mysql://localhost:3306/test
83 | username=root
84 | password=123456
85 | initialSize=2
86 | maxActive=15
87 | maxIdle=2
88 | minIdle=1
89 | maxWait=30000
90 | ```
91 | 这些配置的解释请见[BasicDataSource Configuration Parameters](http://commons.apache.org/proper/commons-dbcp/configuration.html)。
92 |
93 | **HelloServlet.java源码:**
94 | ```java
95 | package me.letiantian.servlet;
96 |
97 | import java.io.IOException;
98 | import java.io.PrintWriter;
99 | import java.sql.Connection;
100 | import java.sql.PreparedStatement;
101 | import java.sql.ResultSet;
102 | import java.util.Properties;
103 | import javax.servlet.annotation.WebServlet;
104 | import javax.servlet.http.HttpServlet;
105 | import javax.servlet.http.HttpServletRequest;
106 | import javax.servlet.http.HttpServletResponse;
107 | import javax.sql.DataSource;
108 |
109 | import org.apache.commons.dbcp.BasicDataSourceFactory;
110 |
111 |
112 | @WebServlet(name = "HelloServlet", urlPatterns = {"/hello"})
113 | public class HelloServlet extends HttpServlet {
114 |
115 | protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
116 | response.setContentType("text/html;charset=UTF-8");
117 | PrintWriter out = response.getWriter();
118 | try{
119 | Properties properties=new Properties();
120 | properties.load(getServletContext().getResourceAsStream("/WEB-INF/dbcp.properties"));
121 | DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
122 | Connection conn = dataSource.getConnection();
123 | String sql = "select 1+1 as result;";
124 | PreparedStatement pstmt = conn.prepareStatement(sql);
125 | ResultSet rs = pstmt.executeQuery();
126 |
127 | if (rs.next()) {
128 | int result = rs.getInt("result");
129 | out.println("result: " + result);
130 | }
131 |
132 | rs.close();
133 | pstmt.close();
134 | conn.close();
135 |
136 | } catch (Exception ex) {
137 | out.println(ex.getMessage());
138 | }
139 | }
140 |
141 | @Override
142 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
143 | processRequest(request, response);
144 | }
145 |
146 |
147 | @Override
148 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
149 | processRequest(request, response);
150 | }
151 |
152 | }
153 | ```
154 |
155 | 运行项目,浏览器访问`http://localhost:8084/Project_0007_DBCP/hello`:
156 | 
157 |
158 |
159 | ## 改进:将初始化的连接池放到Servlet上下文中
160 | 上面代码中是再servlet中初始化连接池,更好的方法是再Listener中初始化,并将连接池作为属性放入servlet上下文中。
161 |
162 | 源文件以及代码有所变化,项目结构如下:
163 | 
164 |
165 | DBCPListener.java内容如下:
166 | ```java
167 | package me.letiantian.listener;
168 |
169 | import java.util.Properties;
170 | import javax.servlet.ServletContext;
171 | import javax.servlet.ServletContextEvent;
172 | import javax.servlet.ServletContextListener;
173 | import javax.servlet.annotation.WebListener;
174 | import javax.sql.DataSource;
175 | import org.apache.commons.dbcp.BasicDataSourceFactory;
176 |
177 | @WebListener
178 | public class DBCPListener implements ServletContextListener{
179 |
180 | // 应用启动时,该方法被调用
181 | @Override
182 | public void contextInitialized(ServletContextEvent sce) {
183 | try {
184 | System.out.println("设置数据库连接池");
185 | ServletContext application = sce.getServletContext();
186 | Properties properties=new Properties();
187 | properties.load(application.getResourceAsStream("/WEB-INF/dbcp.properties"));
188 | DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
189 | application.setAttribute("dataSource", dataSource);
190 | }
191 | catch(Exception ex) {
192 | System.err.println("数据库连接池设置出现异常:" + ex.getMessage());
193 | }
194 | }
195 |
196 | // 应用关闭时,该方法被调用
197 | @Override
198 | public void contextDestroyed(ServletContextEvent sce) {
199 |
200 | }
201 |
202 | }
203 | ```
204 |
205 | HelloServlet.java内容如下:
206 | ```java
207 | package me.letiantian.servlet;
208 |
209 | import java.io.IOException;
210 | import java.io.PrintWriter;
211 | import java.sql.Connection;
212 | import java.sql.PreparedStatement;
213 | import java.sql.ResultSet;
214 | import javax.servlet.annotation.WebServlet;
215 | import javax.servlet.http.HttpServlet;
216 | import javax.servlet.http.HttpServletRequest;
217 | import javax.servlet.http.HttpServletResponse;
218 | import javax.sql.DataSource;
219 |
220 | @WebServlet(name = "HelloServlet", urlPatterns = {"/hello"})
221 | public class HelloServlet extends HttpServlet {
222 |
223 | protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
224 | response.setContentType("text/html;charset=UTF-8");
225 | PrintWriter out = response.getWriter();
226 | try {
227 | DataSource dataSource = (DataSource) getServletContext().getAttribute("dataSource");
228 | Connection conn = dataSource.getConnection();
229 | String sql = "select name from user;";
230 | PreparedStatement pstmt = conn.prepareStatement(sql);
231 | ResultSet rs = pstmt.executeQuery();
232 |
233 | while (rs.next()) {
234 | String name = rs.getString("name");
235 | out.println("result: " + name + "");
236 | }
237 |
238 | rs.close();
239 | pstmt.close();
240 | conn.close();
241 |
242 | } catch (Exception ex) {
243 | out.println(ex.getMessage());
244 | }
245 | }
246 |
247 | @Override
248 | protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
249 | processRequest(request, response);
250 | }
251 |
252 |
253 | @Override
254 | protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
255 | processRequest(request, response);
256 | }
257 |
258 | }
259 | ```
260 |
261 | 启动项目,可以看到Tomcat输出:
262 | ```plain
263 | 设置数据库连接池
264 | ```
265 |
266 | 浏览器输出:
267 | 
268 |
269 | 查看一下mysql的连接:
270 | ```plain
271 | mysql> show processlist;
272 | +----+------+-----------------+------+---------+------+-------+------------------+
273 | | Id | User | Host | db | Command | Time | State | Info |
274 | +----+------+-----------------+------+---------+------+-------+------------------+
275 | | 45 | root | localhost | test | Query | 0 | init | show processlist |
276 | | 77 | root | localhost:41770 | test | Sleep | 300 | | NULL |
277 | | 78 | root | localhost:41771 | test | Sleep | 300 | | NULL |
278 | | 83 | root | localhost:41790 | test | Sleep | 274 | | NULL |
279 | | 84 | root | localhost:41791 | test | Sleep | 69 | | NULL |
280 | +----+------+-----------------+------+---------+------+-------+------------------+
281 | 5 rows in set (0.00 sec)
282 | ```
283 |
284 | 关闭Tomcat,查看数据库连接:
285 | ```plain
286 | mysql> show processlist;
287 | +----+------+-----------+------+---------+------+-------+------------------+
288 | | Id | User | Host | db | Command | Time | State | Info |
289 | +----+------+-----------+------+---------+------+-------+------------------+
290 | | 45 | root | localhost | test | Query | 0 | init | show processlist |
291 | +----+------+-----------+------+---------+------+-------+------------------+
292 | 1 row in set (0.00 sec)
293 | ```
294 |
295 | ## DBUtils
296 | 使用DBUtils可以更加方便的操作数据库,可以参考[DBUtils简明教程](http://www.letiantian.me/2015-03-09-apache-dbutils/)。
297 |
298 |
299 | ## 资料
300 | 官网
301 | [DBCP,C3P0,Tomcat_JDBC 性能及稳定性测试](http://www.open-open.com/lib/view/open1329182303124.html)
302 | [数据连接池DBCP参数介绍](http://my.oschina.net/robinsonlu/blog/77759)
303 | [DBCP数据库连接池的使用](http://my.oschina.net/donghongyu/blog/190494)
304 |
--------------------------------------------------------------------------------
/01-03.md:
--------------------------------------------------------------------------------
1 | 01-03、JdbcTemplate
2 | ---
3 |
4 | JdbcTemplate是Spring MVC内置的对JDBC的一个封装。
5 |
6 | ## 数据库准备
7 | MySQL 5.6。
8 |
9 | ```sql
10 | --创建数据库
11 | CREATE DATABASE IF NOT EXISTS `test` DEFAULT CHARSET utf8 COLLATE utf8_general_ci;
12 | USE `test`;
13 | --创建table
14 | CREATE TABLE IF NOT EXISTS user
15 | (
16 | `id` int AUTO_INCREMENT,
17 | `name` varchar(255),
18 | `email` varchar(255),
19 | `age` varchar(255),
20 | `passwd` varchar(255),
21 | PRIMARY KEY (`id`),
22 | UNIQUE KEY (`name`),
23 | UNIQUE KEY (`email`)
24 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
25 | ---插入若干数据
26 | INSERT INTO user (`name`, `email`, `age`, `passwd`)
27 | VALUES ('user01', 'user01@163.com', 20, password('123'));
28 |
29 | INSERT INTO user (`name`, `email`, `age`, `passwd`)
30 | VALUES ('user02', 'user02@163.com', 20, password('456'));
31 |
32 | INSERT INTO user (`name`, `email`, `age`, `passwd`)
33 | VALUES ('用户03', 'user03@163.com', 20, password('456'));
34 | ```
35 |
36 | ## 示例1
37 | 继续使用的上一节[01-02、使用Spring MVC构建Hello World](./01-02.md)中创建的项目。
38 |
39 | 项目结构如下:
40 | 
41 |
42 | 图中红线下的文件是新增或者修改的文件。
43 |
44 | MySQL的JDBC封装`mysql-connector-java-**.jar`别忘了放到Libraries里。
45 |
46 | ### 源码
47 |
48 | **SelectController.java源码:**
49 | ```java
50 | package me.letiantian.controller;
51 |
52 | import java.util.List;
53 | import java.util.Map;
54 | import javax.servlet.http.HttpServletRequest;
55 | import javax.servlet.http.HttpServletResponse;
56 | import org.springframework.beans.factory.annotation.Autowired;
57 | import org.springframework.web.servlet.ModelAndView;
58 | import org.springframework.web.servlet.mvc.Controller;
59 | import org.springframework.jdbc.core.JdbcTemplate;
60 |
61 | import me.letiantian.service.UserService;
62 |
63 | public class SelectController implements Controller{
64 |
65 | @Autowired
66 | private UserService userDao;
67 |
68 | @Autowired
69 | private JdbcTemplate jdbcTemplate;
70 |
71 | @Override
72 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
73 | response.setContentType("text/html;charset=UTF-8");
74 | ModelAndView mv = new ModelAndView();
75 |
76 | List users = jdbcTemplate.queryForList("SELECT * FROM user");
77 | mv.addObject("users", users);
78 |
79 | Map user1 = userDao.getUserById(1);
80 | mv.addObject("user1", user1);
81 |
82 | Map user2 = jdbcTemplate.queryForMap("SELECT * FROM user WHERE id=2");
83 | mv.addObject("user2", user2);
84 |
85 | mv.addObject("message", "无错误信息");
86 | mv.setViewName("select");
87 | return mv;
88 | }
89 |
90 | }
91 | ```
92 |
93 | **UserService.java源码: **
94 | ```java
95 | package me.letiantian.service;
96 |
97 | import java.util.Map;
98 | import org.springframework.beans.factory.annotation.Autowired;
99 | import org.springframework.jdbc.core.JdbcTemplate;
100 | import org.springframework.stereotype.Service;
101 |
102 | @Service
103 | public class UserService {
104 |
105 | @Autowired
106 | private JdbcTemplate jdbcTemplate;
107 |
108 | public Map getUserById(int id) {
109 |
110 | Map user = jdbcTemplate.queryForMap("SELECT * FROM user WHERE id=?", new Object[] {id});
111 | return user;
112 |
113 | }
114 |
115 | }
116 | ```
117 |
118 | **select.jsp源码: **
119 | ```html
120 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
121 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
122 |
123 |
124 |
125 |
126 | JSP Page
127 |
128 |
129 | Hello World!
130 |
131 |
132 |
133 |
134 |
135 | :
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 | ${message}
169 |
170 |
171 | ```
172 |
173 | **dispatcher-servlet.xml源码:**
174 | ```xml
175 |
176 |
177 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 | indexController
196 | helloController
197 | selectController
198 |
199 |
200 |
201 |
202 |
206 |
207 |
210 |
211 |
213 |
214 |
216 |
217 |
218 |
219 |
220 | ```
221 |
222 | 该文件中新增加了`selectController`,以及` `以使得`@Autowired`能够工作。
223 |
224 | **applicationContext.xml源码:**
225 | ```xml
226 |
227 |
237 |
238 |
239 |
240 |
241 |
247 |
248 |
249 |
250 |
251 |
252 |
253 | ```
254 | `dataSource`设置程MySQL,并注入到`jdbcTemplate`。
255 |
256 | **运行项目,浏览器访问:**
257 | 
258 |
259 |
260 | ## 资料
261 | **JdbcTemplate中的有多种查询方法,可以参考:**
262 | [JdbcTemplate 查询](http://www.cnblogs.com/shitianzeng/articles/2318995.html)
263 | [Spring JdbcTemplate方法详解](http://blog.csdn.net/dyllove98/article/details/7772463)
264 |
265 | **上面的JSP中用到了JSTL,以下几篇文件可以看一下:**
266 | [在JSTL EL中处理java.util.Map,及嵌套List的情况](http://my.oschina.net/letiantian/blog/511920)
267 | [JSP 标准标签库(JSTL)](http://www.runoob.com/jsp/jsp-jstl.html)
268 |
269 | **JdbcTemplate也可以使用事务,有声明式和编程式两种方法:**
270 | [Spring Declarative Transactions](http://www.simplespringtutorial.com/springDeclarativeTransactions.html)
271 | [Spring Programmatic Transactions](http://www.simplespringtutorial.com/springProgrammaticTransactions.html)
272 | [Spring Programmatic Transaction Management](http://www.tutorialspoint.com/spring/programmatic_management.htm)
273 | [Spring JdbcTemplate 与 事务管理](http://blog.sina.com.cn/s/blog_63f08ebf0100orev.html)
274 | [Transactions with JdbcTemplate](http://www.javacreed.com/transactions-with-jdbctemplate/)
275 |
276 |
277 | **如何使用连接池?**
278 | [JDBC Database connection pool in Spring FrameWork - How to SetUp Example](http://javarevisited.blogspot.jp/2012/06/jdbc-database-connection-pool-in-spring.html)
279 | [Setup Connection Pooling in Spring MVC](http://stackoverflow.com/questions/3552831/setup-connection-pooling-in-spring-mvc)
280 |
281 | **其他:**
282 | [Spring MVC with JdbcTemplate Example](http://www.codejava.net/frameworks/spring/spring-mvc-with-jdbctemplate-example)
283 | [Spring MVC and List Example](http://www.mkyong.com/spring-mvc/spring-mvc-and-list-example/)
284 |
--------------------------------------------------------------------------------
/00-04.md:
--------------------------------------------------------------------------------
1 | 00-04、理解Servlet
2 | ---
3 |
4 | 本文依然使用[00-03、从JSP开始](./00-03.md)中创建的项目HelloJSP。
5 |
6 | 本文主要有以下内容:
7 |
8 | * 如何使用Servlet编写Hello Servlet
9 | * 如何将Servlet与URL对应起来
10 | * Servlet如何调用JSP
11 | * Servlet如何返回JSON数据
12 | * 如何编写一个Dispatcher
13 |
14 |
15 | ## Hello Servlet
16 | 项目结构如下:
17 |
18 | 
19 |
20 | `HelloServlet.java`内容如下:
21 | ```java
22 | package me.letiantian.servlet;
23 |
24 | import java.io.IOException;
25 | import java.io.PrintWriter;
26 | import javax.servlet.ServletException;
27 | import javax.servlet.http.HttpServlet;
28 | import javax.servlet.http.HttpServletRequest;
29 | import javax.servlet.http.HttpServletResponse;
30 |
31 | public class HelloServlet extends HttpServlet {
32 |
33 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
34 | throws ServletException, IOException {
35 | response.setContentType("text/html;charset=UTF-8");
36 | try (PrintWriter out = response.getWriter()) {
37 | out.println("");
38 | out.println("");
39 | out.println("");
40 | out.println("Servlet HelloServlet ");
41 | out.println("");
42 | out.println("");
43 | out.println("Servlet HelloServlet at " + request.getContextPath() + " ");
44 | out.println("");
45 | out.println("");
46 | }
47 | }
48 |
49 | @Override
50 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
51 | throws ServletException, IOException {
52 | processRequest(request, response);
53 | }
54 |
55 | @Override
56 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
57 | throws ServletException, IOException {
58 | processRequest(request, response);
59 | }
60 |
61 | }
62 |
63 | ```
64 | HTTP最常见的方法是GET和POST,在一个Servlet中对应的处理方法分别是doGet()和doPost()。
65 | `response.setContentType("text/html;charset=UTF-8");` 用来设置HTTP响应头中的Content-Type。
66 | PrintWriter对象out的输出内容则是响应正文。
67 |
68 |
69 | `web.xml`内容如下:
70 | ```xml
71 |
72 |
73 |
74 | HelloServlet
75 | me.letiantian.servlet.HelloServlet
76 |
77 |
78 | HelloServlet
79 | /HelloServlet
80 |
81 |
82 |
83 | 30
84 |
85 |
86 |
87 | ```
88 | 在这个配置中,`me.letiantian.servlet.HelloServlet`与URL`/HelloServlet`对应。
89 | `session-timeout`设置了session的有效时间,单位是分钟(不过目前的程序里还没用过session)。
90 |
91 | 浏览器访问`http://127.0.0.1:8084/HelloJSP`会显示404;访问`http://127.0.0.1:8084/HelloJSP/HelloServlet`会显示`Servlet HelloServlet at /HelloJSP`,这也正是`me.letiantian.servlet.HelloServlet`输出的HTML的渲染结果。
92 |
93 |
94 | ### 也可以使用注解将Servlet和URL对应起来
95 |
96 | 首先清空web.xml中关于URL的配置,web.xml最终内容如下:
97 | ```xml
98 |
99 |
100 |
101 |
102 |
103 | 30
104 |
105 |
106 |
107 |
108 |
109 | ```
110 | 然后对`me.letiantian.servlet.HelloServlet`类略做修改:
111 | ```java
112 | package me.letiantian.servlet;
113 |
114 | import java.io.IOException;
115 | import java.io.PrintWriter;
116 | import javax.servlet.ServletException;
117 | import javax.servlet.http.HttpServlet;
118 | import javax.servlet.http.HttpServletRequest;
119 | import javax.servlet.http.HttpServletResponse;
120 |
121 | import javax.servlet.annotation.WebServlet;
122 |
123 | @WebServlet("/HelloServlet")
124 | public class HelloServlet extends HttpServlet {
125 | // ......
126 | }
127 | ```
128 |
129 | 重新启动项目,浏览器访问效果和之前是相同的。
130 |
131 |
132 | ## Servlet调用JSP
133 | 改写me.letiantian.servlet.HelloServlet类,内容如下:
134 |
135 | ```java
136 | package me.letiantian.servlet;
137 |
138 | import java.io.IOException;
139 | import java.io.PrintWriter;
140 | import javax.servlet.RequestDispatcher;
141 | import javax.servlet.ServletException;
142 | import javax.servlet.http.HttpServlet;
143 | import javax.servlet.http.HttpServletRequest;
144 | import javax.servlet.http.HttpServletResponse;
145 |
146 | import javax.servlet.annotation.WebServlet;
147 |
148 | @WebServlet("/HelloServlet")
149 | public class HelloServlet extends HttpServlet {
150 |
151 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
152 | throws ServletException, IOException {
153 | response.setContentType("text/html;charset=UTF-8");
154 | request.setAttribute("title", "Hello Servlet");
155 | request.setAttribute("content", "你好");
156 | RequestDispatcher rd = request.getRequestDispatcher("/WEB-INF/jsp/hello.jsp");
157 | rd.forward(request, response);
158 | }
159 |
160 | @Override
161 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
162 | throws ServletException, IOException {
163 | processRequest(request, response);
164 | }
165 |
166 | @Override
167 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
168 | throws ServletException, IOException {
169 | processRequest(request, response);
170 | }
171 |
172 | }
173 | ```
174 |
175 | 在`WEB-INF/`下创建目录`jsp`,然后在`jsp`目录下新建`hello.jsp`,内容如下:
176 | ```html
177 |
178 |
179 |
180 |
181 | ${title}
182 |
183 |
184 | ${content}
185 |
186 |
187 | ```
188 |
189 | 重启该项目,访问`http://127.0.0.1:8084/HelloJSP/HelloServlet`:
190 | ```plain
191 | $ curl -i http://127.0.0.1:8084/HelloJSP/HelloServlet
192 | HTTP/1.1 200 OK
193 | Server: Apache-Coyote/1.1
194 | Set-Cookie: JSESSIONID=7CCCFD5467F8330066F827623802FB23; Path=/HelloJSP/; HttpOnly
195 | Content-Type: text/html;charset=UTF-8
196 | Content-Length: 215
197 | Date: Fri, 18 Sep 2015 08:09:58 GMT
198 |
199 |
200 |
201 |
202 |
203 |
204 | Hello Servlet
205 |
206 |
207 | 你好
208 |
209 |
210 | ```
211 |
212 | ## CSS等静态文件放在什么地方
213 | 在项目下建立static目录,再这个目录下添加`test.js`,内容如下:
214 | ```
215 | console.log("hello world");
216 | ```
217 | 在`web.xml`添加以下内容:
218 | ```xml
219 |
220 | default
221 | *.jpg
222 |
223 |
224 |
225 | default
226 | *.png
227 |
228 |
229 |
230 | default
231 | *.js
232 |
233 |
234 |
235 | default
236 | *.css
237 |
238 | ```
239 | 此时,项目结构如下:
240 | 
241 |
242 | 启动项目,访问
243 | ```plain
244 | $ curl -i http://localhost:8084/HelloJSP/static/test.js
245 | HTTP/1.1 200 OK
246 | Server: Apache-Coyote/1.1
247 | Accept-Ranges: bytes
248 | ETag: W/"27-1442566151000"
249 | Last-Modified: Fri, 18 Sep 2015 08:49:11 GMT
250 | Content-Type: application/javascript
251 | Content-Length: 27
252 | Date: Fri, 18 Sep 2015 08:58:00 GMT
253 |
254 | console.log("hello world");
255 | ```
256 |
257 | ```plain
258 | $ curl -i http://localhost:8084/HelloJSP/static/test.js?time=123
259 | HTTP/1.1 200 OK
260 | Server: Apache-Coyote/1.1
261 | Accept-Ranges: bytes
262 | ETag: W/"27-1442566151000"
263 | Last-Modified: Fri, 18 Sep 2015 08:49:11 GMT
264 | Content-Type: application/javascript
265 | Content-Length: 27
266 | Date: Fri, 18 Sep 2015 08:58:09 GMT
267 |
268 | console.log("hello world");
269 | ```
270 |
271 | ## Servlet如何返回JSON数据
272 |
273 | 将
274 | ```
275 | response.setContentType("text/html;charset=UTF-8");
276 | ```
277 | 修改为
278 | ```
279 | response.setContentType("application/json;charset=UTF-8");
280 | ```
281 | 。
282 |
283 | `out.println`输出JSON格式的字符串即可。
284 |
285 |
286 | ## 编写Dispatcher
287 | 基于以上的学习,已经可以编写一个分发器了。
288 | 将HelloServlet.java修改为DispatcherServlet.java,内容修改为:
289 | ```java
290 | package me.letiantian.servlet;
291 |
292 | import java.io.IOException;
293 | import java.io.PrintWriter;
294 | import javax.servlet.ServletException;
295 | import javax.servlet.http.HttpServlet;
296 | import javax.servlet.http.HttpServletRequest;
297 | import javax.servlet.http.HttpServletResponse;
298 |
299 | import javax.servlet.annotation.WebServlet;
300 |
301 | @WebServlet("/")
302 | public class HelloServlet extends HttpServlet {
303 |
304 | protected void processRequest(HttpServletRequest request, HttpServletResponse response)
305 | throws ServletException, IOException {
306 | response.setContentType("text/plain;charset=UTF-8");
307 | try (PrintWriter out = response.getWriter()) {
308 | out.println("context: " + request.getContextPath());
309 | out.println("request uri: " + request.getRequestURI());
310 | out.println("params: " + request.getParameterMap());
311 | }
312 | }
313 |
314 | @Override
315 | protected void doGet(HttpServletRequest request, HttpServletResponse response)
316 | throws ServletException, IOException {
317 | processRequest(request, response);
318 | }
319 |
320 | @Override
321 | protected void doPost(HttpServletRequest request, HttpServletResponse response)
322 | throws ServletException, IOException {
323 | processRequest(request, response);
324 | }
325 |
326 | }
327 | ```
328 | 运行项目,访问结果如下:
329 | ```
330 | $ curl http://localhost:8084/HelloJSP/user
331 | context: /HelloJSP
332 | request uri: /HelloJSP/user
333 | params: {}
334 | ```
335 | ```
336 | $ curl http://localhost:8084/HelloJSP/user?name=letian
337 | context: /HelloJSP
338 | request uri: /HelloJSP/user
339 | params: {name=[Ljava.lang.String;@49ea47b4}
340 | ```
341 | ```
342 | $ curl http://localhost:8084/HelloJSP/static/test.js
343 | console.log("hello world");
344 | ```
345 | (这个代码并没什么用~)
346 |
347 | 从这段代码中可以看到,我们可以通过request对象得到HTTP请求信息,特别是request URI。在这个程序的基础上,我们
348 | 可以继续扩充它,使得其遇到某个URI,就调用指定的处理函数。慢慢地补充,一个框架就出来了。
349 |
350 |
351 | ## 资料
352 |
353 | 本节中,JSP使用了表达式语言,可以参考:
354 | [JSTL 入门: 表达式语言](http://www.ibm.com/developerworks/cn/java/j-jstl0211/index.html)
355 | [JSP 表达式语言](http://www.runoob.com/jsp/jsp-expression-language.html)
356 |
--------------------------------------------------------------------------------
/01-06.md:
--------------------------------------------------------------------------------
1 | 01-06、校验器
2 | ---
3 |
4 | 校验器,Validator。
5 |
6 | 在处理带有表单数据的HTTP请求时,通常这样做:
7 |
8 | ```plain
9 | if (表单数据符合要求) {
10 | 处理数据,返回结果;
11 | } else {
12 | 返回结果,提示用户重新输入数据;
13 | }
14 | ```
15 |
16 | 判断表单数据是否符合要求这就是校验器该做的事情。我们可以自己编写校验类,也可以使用Spring MVC自带的相关类。
17 |
18 | ## 将表单数据绑定到对象中
19 | 项目结构如下:
20 | 
21 |
22 | ### 源码
23 | **web.xml**
24 | ```xml
25 |
26 |
27 |
28 | contextConfigLocation
29 | /WEB-INF/applicationContext.xml
30 |
31 |
32 | org.springframework.web.context.ContextLoaderListener
33 |
34 |
35 | dispatcher
36 | org.springframework.web.servlet.DispatcherServlet
37 | 2
38 |
39 |
40 | dispatcher
41 | /
42 |
43 |
44 |
45 | 30
46 |
47 |
48 |
49 | redirect.jsp
50 |
51 |
52 | ```
53 |
54 | **applicationContext.xml**
55 | ```xml
56 |
57 |
65 |
66 |
67 | ```
68 |
69 | **dispatcher-servlet.xml**
70 | ```xml
71 |
72 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 | indexController
94 |
95 |
96 |
97 |
98 |
102 |
103 |
106 |
107 |
108 | ```
109 |
110 | **hello/input.jsp**
111 | ```html
112 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
113 |
114 |
115 |
116 |
117 | JSP Page
118 |
119 |
120 |
126 |
127 |
128 | ```
129 |
130 | **hello/output.jsp**
131 | ```plain
132 | <%@page contentType="text/plain" pageEncoding="UTF-8"%>
133 | first name: ${person.firstName}
134 | second name: ${person.secondName}
135 | ```
136 |
137 | **Person.java**
138 | ```java
139 | package me.letiantian.form;
140 |
141 | public class Person {
142 |
143 | private String firstName;
144 | private String secondName;
145 |
146 | public String getFirstName() {
147 | return firstName;
148 | }
149 |
150 | public void setFirstName(String firstName) {
151 | this.firstName = firstName;
152 | }
153 |
154 | public String getSecondName() {
155 | return secondName;
156 | }
157 |
158 | public void setSecondName(String secondName) {
159 | this.secondName = secondName;
160 | }
161 |
162 | }
163 | ```
164 |
165 | **HelloController.java**
166 | ```java
167 | package me.letiantian.controller;
168 |
169 | import java.io.PrintWriter;
170 | import javax.servlet.http.HttpServletRequest;
171 | import javax.servlet.http.HttpServletResponse;
172 | import org.springframework.stereotype.Controller;
173 | import org.springframework.ui.Model;
174 | import org.springframework.web.bind.annotation.PathVariable;
175 | import org.springframework.web.bind.annotation.RequestMapping;
176 | import org.springframework.web.bind.annotation.RequestMethod;
177 |
178 | import me.letiantian.form.Person;
179 | import org.springframework.web.bind.annotation.ModelAttribute;
180 |
181 | @Controller
182 | @RequestMapping("/hello")
183 | public class HelloController{
184 |
185 | @RequestMapping(value = "")
186 | public String index() {
187 | return "index";
188 | }
189 |
190 | @RequestMapping(value = "/input")
191 | public String input() {
192 | return "hello/input";
193 | }
194 |
195 | @RequestMapping(value = "/output")
196 | public String output(Person person, Model model) {
197 | model.addAttribute("person", person);
198 | return "hello/output";
199 | }
200 |
201 | // @RequestMapping(value = "/output")
202 | // public String output(@ModelAttribute(value="person") Person person, Model model) {
203 | // return "hello/output";
204 | // }
205 |
206 | }
207 | ```
208 |
209 | 注意,
210 | ```java
211 | @RequestMapping(value = "/output")
212 | public String output(Person person, Model model) {
213 | model.addAttribute("person", person);
214 | return "hello/output";
215 | }
216 | ```
217 | 和
218 | ```java
219 | @RequestMapping(value = "/output")
220 | public String output(@ModelAttribute(value="person") Person person, Model model) {
221 | return "hello/output";
222 | }
223 | ```
224 |
225 | 是一样的。
226 |
227 | ### 浏览器访问
228 |
229 | 表单填入信息:
230 | 
231 | 提交表单后:
232 | 
233 |
234 |
235 | ## 校验数据
236 |
237 | ### hello/input.jsp修改如下
238 | ```html
239 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
240 | <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
241 | <%@taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
242 |
243 |
244 |
245 |
246 | JSP Page
247 |
250 |
251 |
252 |
253 |
254 | firstName:
255 | secondName:
256 |
257 |
258 |
259 |
260 |
261 | ```
262 |
263 | 注意` type) {
325 | return Person.class.isAssignableFrom(type);
326 | }
327 |
328 | @Override
329 | public void validate(Object o, Errors errors) {
330 | Person person = (Person) o;
331 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "firstName", null, "firstName不能为空");
332 | ValidationUtils.rejectIfEmptyOrWhitespace(errors, "secondName", null, "secondName不能为空");
333 | if (person.getFirstName().length() < 2) {
334 | errors.rejectValue("firstName", null, "firstName太短");
335 | }
336 | }
337 | }
338 | ```
339 |
340 | ### 测试
341 | **第1组:**
342 |
343 | 
344 | 
345 |
346 | **第2组:**
347 |
348 | 
349 | 
350 |
351 | **第3组:**
352 |
353 | 
354 | 
355 |
--------------------------------------------------------------------------------
/01-02.md:
--------------------------------------------------------------------------------
1 | 01-02、使用Spring MVC构建Hello World
2 | ---
3 |
4 | 本文演示如何使用Spring MVC做出最简单的Hello World应用。
5 |
6 | ## 示例1
7 | 项目创建和之前一样,不过在最后一步要选择Spring Web MVC:
8 | 
9 |
10 | 项目结构如下:
11 | 
12 |
13 | ### web.xml源码:
14 | ```xml
15 |
16 |
17 |
18 | contextConfigLocation
19 | /WEB-INF/applicationContext.xml
20 |
21 |
22 |
23 | org.springframework.web.context.ContextLoaderListener
24 |
25 |
26 |
27 | dispatcher
28 | org.springframework.web.servlet.DispatcherServlet
29 | 2
30 |
31 |
32 |
33 | dispatcher
34 | *.htm
35 |
36 |
37 |
38 |
39 | 30
40 |
41 |
42 |
43 | redirect.jsp
44 |
45 |
46 | ```
47 | 如果遇到匹配*.htm的URL,会使用`org.springframework.web.servlet.DispatcherServlet`来处理。
48 |
49 | ### applicationContext.xml源码:
50 | ```xml
51 |
52 |
53 |
61 |
62 |
72 |
73 |
74 |
75 |
76 | ```
77 | applicationContext.xml是Spring的配置文件。
78 |
79 | ### dispatcher-servlet.xml源码:
80 | ```xml
81 |
82 |
83 |
91 |
92 |
93 |
94 |
99 |
100 |
101 |
102 | indexController
103 |
104 |
105 |
106 |
107 |
111 |
112 |
115 |
118 |
119 |
120 | ```
121 |
122 | 在` `定义了JSP模板文件的位置和后缀(这样其他地方就可以省略后缀了)。
123 |
124 | URL为`index.htm`时,对应的控制器是`indexController`,其调用了`/WEB-INF/jsp/`下的模板`index.jsp`。
125 |
126 | ### redirect.jsp源码
127 | ```jsp
128 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
129 | <% response.sendRedirect("index.htm"); %>
130 | ```
131 |
132 | ### index.jsp源码
133 |
134 | ```html
135 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
136 |
138 |
139 |
140 |
141 |
142 | Welcome to Spring Web MVC project
143 |
144 |
145 |
146 | Hello! This is the default welcome page for a Spring Web MVC project.
147 | To display a different welcome page for this project, modify
148 | index.jsp , or create your own welcome page then change
149 | the redirection in redirect.jsp to point to the new
150 | welcome page and also update the welcome-file setting in
151 | web.xml .
152 |
153 |
154 | ```
155 |
156 | 运行项目,打开浏览器访问`http://localhost:8084/Project_0102/`,会自动跳转到
157 | `http://localhost:8084/Project_0102/index.htm`,并显示`index.jsp`的内容。
158 |
159 | ### Hello World
160 | 修改dispatcher-servlet.xml,将` `修改为:
161 | ```xml
162 |
163 |
164 |
165 | indexController
166 | helloController
167 |
168 |
169 |
170 | ```
171 |
172 | 并添加:
173 | ```xml
174 |
176 | ```
177 |
178 | HelloController.java的源码如下:
179 | ```java
180 | package me.letiantian.controller;
181 |
182 | import javax.servlet.http.HttpServletRequest;
183 | import javax.servlet.http.HttpServletResponse;
184 | import org.springframework.web.servlet.ModelAndView;
185 | import org.springframework.web.servlet.mvc.Controller;
186 |
187 | public class HelloController implements Controller{
188 |
189 | @Override
190 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
191 |
192 | ModelAndView mv = new ModelAndView();
193 | mv.addObject("message", "Hello World!你好");
194 | mv.setViewName("hello");
195 | return mv;
196 | }
197 |
198 | }
199 | ```
200 | 模板`hello.jsp`的源码如下:
201 | ```html
202 |
203 |
204 | Hello world
205 |
206 |
207 | ${message}
208 |
209 |
210 | ```
211 |
212 | 创建static目录,在static目录下创建test.js,内容如下:
213 | ```js
214 | console.log("hello world");
215 | ```
216 |
217 | 在`web.xml`中添加:
218 | ```xml
219 |
220 | default
221 | *.jpg
222 |
223 |
224 |
225 | default
226 | *.png
227 |
228 |
229 |
230 | default
231 | *.js
232 |
233 |
234 |
235 | default
236 | *.css
237 |
238 | ```
239 |
240 | 好了,现在的项目结构如下:
241 | 
242 |
243 | 浏览器访问结果:
244 | 
245 | 
246 |
247 | 乱码了~囧~
248 |
249 | **解决方法:**
250 | 在`HelloController.java`加入`response.setContentType("text/html;charset=UTF-8");`:
251 | ```java
252 | package me.letiantian.controller;
253 |
254 | import javax.servlet.http.HttpServletRequest;
255 | import javax.servlet.http.HttpServletResponse;
256 | import org.springframework.web.servlet.ModelAndView;
257 | import org.springframework.web.servlet.mvc.Controller;
258 |
259 | public class HelloController implements Controller{
260 |
261 | @Override
262 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
263 | response.setContentType("text/html;charset=UTF-8"); // 新加入的内容
264 | ModelAndView mv = new ModelAndView();
265 | mv.addObject("message", "Hello World!你好");
266 | mv.setViewName("hello");
267 | return mv;
268 | }
269 |
270 | }
271 | ```
272 |
273 |
274 | ## 示例2
275 |
276 | ### 换种方法配置静态资源
277 |
278 | 删掉在`web.xml`中的:
279 | ```xml
280 |
281 | default
282 | *.jpg
283 |
284 |
285 |
286 | default
287 | *.png
288 |
289 |
290 |
291 | default
292 | *.js
293 |
294 |
295 |
296 | default
297 | *.css
298 |
299 | ```
300 | 在`dispatcher-servlet.xml`中增加以下内容:
301 | ```xml
302 |
303 |
304 |
314 |
315 |
316 |
317 |
318 |
319 | ```
320 |
321 | 注意,在beans的属性中增加了`xmlns:mvc="http://www.springframework.org/schema/mvc"`,属性`xsi:schemaLocation`中增加了`http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd`。
322 |
323 |
324 | ### 不再使用任何后缀(例如.html,.jsp)
325 |
326 | 将`redirect.jsp`修改为:
327 | ```jsp
328 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
329 | <% response.sendRedirect("index"); %>
330 | ```
331 |
332 | 将web.xml中的:
333 | ```xml
334 |
335 | dispatcher
336 | *.htm
337 |
338 | ```
339 |
340 | 修改为:
341 | ```xml
342 |
343 | dispatcher
344 | /
345 |
346 | ```
347 |
348 | 将`dispatcher-servlet.xml`中的:
349 | ```xml
350 |
351 |
352 |
353 | indexController
354 | helloController
355 |
356 |
357 |
358 | ```
359 |
360 | 修改为:
361 | ```xml
362 |
363 |
364 |
365 | indexController
366 | helloController
367 |
368 |
369 |
370 | ```
371 |
372 | 然后,浏览器访问`http://localhost:8084/Project_0102/hello`。
373 |
374 |
375 | ## 示例3
376 |
377 | 这个示例展示如何获取URL中的数据。
378 |
379 | 修改`HelloController.java`:
380 | ```java
381 | package me.letiantian.controller;
382 |
383 | import javax.servlet.http.HttpServletRequest;
384 | import javax.servlet.http.HttpServletResponse;
385 | import org.springframework.web.servlet.ModelAndView;
386 | import org.springframework.web.servlet.mvc.Controller;
387 |
388 | public class HelloController implements Controller{
389 |
390 | @Override
391 | public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
392 | response.setContentType("text/html;charset=UTF-8");
393 | ModelAndView mv = new ModelAndView();
394 | mv.addObject("name", request.getParameter("name"));
395 | mv.setViewName("hello");
396 | return mv;
397 | }
398 |
399 | }
400 | ```
401 |
402 | 修改`hello.jsp`:
403 | ```html
404 | <%@page contentType="text/html" pageEncoding="UTF-8"%>
405 |
406 |
407 | Hello world
408 |
409 |
410 | ${pageContext.request.contextPath}
411 |
412 |
416 |
417 | 提交的数据: ${name}
418 |
419 |
420 |
421 | ```
422 | `${pageContext.request.contextPath}`的输出是`/Project_0102`。
423 | 浏览器访问:
424 | 
425 |
426 | 再编辑JSP文件时候遇到了这样的问题:
427 |
428 | > The header.jspf contains characters which will probably be damaged during
429 | conversion to the ISO-8859-1 character set.
430 | Do you want to save the file using this character set?
431 |
432 | 解决办法见[http://stackoverflow.com/questions/15499182/netbeans-forces-me-to-save-in-specific-encoding](http://stackoverflow.com/questions/15499182/netbeans-forces-me-to-save-in-specific-encoding)。
433 |
434 | ## 资料
435 | - [Chapter 13. Web MVC framework](http://docs.spring.io/spring/docs/2.5.x/reference/mvc.html)
436 | - [Spring MVC – How to include JS or CSS files in a JSP page](http://www.mkyong.com/spring-mvc/spring-mvc-how-to-include-js-or-css-files-in-a-jsp-page/)
437 |
438 | - [dispatcher-servlet.xml and application-context.xml的区别](http://stackoverflow.com/questions/4549034/dispatcher-servlet-xml-and-application-context-xml)
439 |
440 | - [Spring MVC SimpleUrlHandlerMapping example](http://www.mkyong.com/spring-mvc/spring-mvc-simpleurlhandlermapping-example/)
441 | - [springMVC中文乱码问题](http://blog.csdn.net/xuechongyang/article/details/8283924)
442 | - [SpringMVC 基于注解的Controller @RequestMapping @RequestParam.. ](http://blog.csdn.net/lufeng20/article/details/7598801)
443 |
444 | - urlMapping也可以通过注解来定义,例如[Spring 4 MVC Hello World Tutorial – Full Example](http://javahash.com/spring-4-mvc-hello-world-tutorial-full-example/)。
445 |
--------------------------------------------------------------------------------