Content Table

SpringMVC 拦截器

1. 实现拦截器类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package com.xtuer.interceptor;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler) throws Exception {
System.out.println("my interceptor");
return true; // 返回 true 则继续处理
}

@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response,
Object handler,
ModelAndView modelAndView) throws Exception {
String token = UUID.randomUUID().toString().replace("-", "").toUpperCase();
System.out.println(token);
modelAndView.addObject("token", token);
}

@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response,
Object handler, Exception ex) throws Exception {

}
}

Spring MVC 进一步学习

本章主要介绍 Spring MVC 中一些常用的知识点,详细说明请参考官方帮助文档。

@RequestMapping

  • @GetMapping 等价于 @RequestMapping(method = RequestMethod.GET)
  • @PutMapping 等价于 @RequestMapping(method = RequestMethod.PUT)
  • @PostMapping 等价于 @RequestMapping(method = RequestMethod.POST)
  • @DeleteMapping 等价于 @RequestMapping(method = RequestMethod.DELETE)

@PathVariable

取得 URL 路径中匹配的内容,适合 RESTful 的风格。

A @PathVariable argument can be of any simple type such as int, long, Date, etc. Spring automatically converts to the appropriate type or throws a TypeMismatchException if it fails to do so. You can also register support for parsing additional data types.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.xtuer.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class ParameterController {
// {userId} 是 placeholder,里面的内容可以用 @PathVariable 取到
@RequestMapping("/users/{userId}")
@ResponseBody
public String one(@PathVariable Integer userId) {
return userId + "";
}

// 如果变量名和 {} 中的名字不一样,
// 需要用 @PathVariable("nameInPath") 来指定变量要使用路径中的哪一个变量
@RequestMapping("/categories/{categoryName}/products/{productId}")
@ResponseBody
public String two(@PathVariable String categoryName,
@PathVariable("productId") Integer pId) {
return "categoryName: " + categoryName + ", productId: " + pId;
}

// 还支持正则表达式的方式
@RequestMapping("/regex/{text:[a-z]+}-{number:\\d+}")
@ResponseBody
public String three(@PathVariable String text, @PathVariable Integer number) {
return "Text: " + text + ", Number: " + number;
}

// 路径中有 . 时需要用正则,如 http://localhost:8080//question-img/GYYK034C/Aimage002.jpg
@GetMapping("/question-img/{subjectCode}/{imageName:.+}")
public void readQuestionImage(@PathVariable String subjectCode, @PathVariable String imageName) {
...
}
}

测试:

Tomcat 自定义 lib 目录

现在微服务挺流行的,以前的一个项目使用微服务后可能被拆开成了 5 个小项目,但是有的公司服务器不够,很可能把其中几个项目都安装在同一台机器上,甚至这些项目都使用同一个 Tomcat 来运行。

现在假设这些项目都使用 SpringMvc 来开发,以前一个项目的时候,项目的 lib 里放一份 SpringMvc 的 jar 包就可以了,现在因为分成了 5 个项目,则每个项目都在自己的 lib 里带上 SpringMvc 的 jar 包,结果就是比以前多了 4 分 SpringMvc 的 jar 包。

能不能把一份 SpringMvc 的 jar 包放在一个共同的目录下,然后这些项目都共同使用呢?

Tomcat 多域名

一个 Tomcat 可以支持多个域名,需要在 server.xml 中为每一个域名配置一个 Host,参考默认的 localhost 的配置。

安装 Tomcat 后,在 conf/server.xml 中默认有一个 localhost 的 Host:

1
2
3
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t &quot;%r&quot; %s %b"/>
</Host>

术语:

  • 应用:一个域名对应一个 Web 应用
  • 项目:一个域名下可以有多个项目,参考 Tomcat webapps 下的多个项目,例如 ROOT,manager,examples

CKEditor 的使用

CKEditor 是一个非常优秀的 Web 服文本编辑器,提供了非常多的功能和丰富的文档

Constantly leading innovation in the field of rich text editing. Take full control of your content creation process with such unique features as Paste from Word, Advanced Content Filter, widgets, custom HTML formatting and many more.

CKEditor 还有一个很大的优势是它有一个非常强大的插件商店,里面基本都是免费的,推荐 3 个基础,但是很实用的插件:

修改配置 config.js

1
2
3
4
5
6
// 使用上面的几个插件
config.extraPlugins = 'tableresize,preview,colorbutton';

// Simplify the dialog windows.
config.removeDialogTabs = 'image:advanced;image:Link;link:advanced;link:target';
config.removePlugins = 'elementspath';

下面将介绍:

  • 集成 CKEditor
  • 设置 CKEditor
  • 对话框中使用 CKEditor
  • CKEditor 上传图片
  • CKEditor 上传文件

Doc 转换为 HTML

上传 doc 文件到服务器上时,如果需要在浏览器中预览,可以把 doc 转为 pdf,然后使用 pdf.js 在线预览 pdf,也可以把 doc 转为 html,直接在浏览器中打开。POI 可以很简单的把 doc 转为 html。

Word 里的公式使用的矢量格式 WMF,需要转换为 SVG 后才能在浏览器中查看,下面的代码使用了 wmf2svg 进行了转换。发现图片文件的名字以 .wmf 结尾,则给它加上 .svg,并且转换为 SVG 格式的图片。

Semantic Ui 的 Behavior 和 Settings

学习 Semantic Ui 的时候,不少组件的文档里都有 behavior 和 settings,例如 Dimmer, Form Validation, Transition, Tab, Dropdown等,相信不少同学对 behavior 和 settings 应该怎么用摸不着头脑。

Behavior 就是行为,和函数是一回事,写个函数不就好了?但是 Semantic Ui 里偏偏不这样,而是传入 behavior 的名字,然后内部去调用。

Settings(设置) 更是不知道什么时候用啊,既然是设置,那么逻辑上就应该在 behavior 被调用之前先行设置好,这样在 behavior 被调用的时候才会生效,如果在 behavior 被调用后才使用 settings,那么就没有意义了。

从参数上就可以区分是 Settings 还是 Behavior:

  • Settings: 参数是一个 JSON 对象

  • Behavior: 第一个参数是一个字符串,behavior 的名字,后面是其他参数,例如

    1
    $('.dropdown').dropdown('set selected', 2);

下面就以 card 中使用 dimmer 为例,介绍 behavior 和 settings 的使用:

首字母放大缩进

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<style media="screen">
body {
font-family: 'Arial'
}
div {
text-indent: 2em;
}
div:first-letter {
font-size: 3em;
color: gray;
}
</style>
</head>

<body>
<div>焚我残躯,熊熊烈火.生亦何欢,死亦何苦.为善除恶,惟光明故.喜乐悲愁,皆归尘土.怜我世人,忧患实多.怜我世人,忧患实多.</div>
<div>焚我残躯,熊熊烈火.生亦何欢,死亦何苦.为善除恶,惟光明故.喜乐悲愁,皆归尘土.怜我世人,忧患实多.怜我世人,忧患实多.</div>
</body>

</html>

jQuery 的 attr 和 prop

jQuery 中可以使用 attr 和 prop 获取的属性,它们的区别是什么呢?

The segregation of attr() and prop() should help alleviate some of the confusion between HTML attributes and DOM properties. $.fn.prop() grabs the specified DOM property, while $.fn.attr() grabs the specified HTML attribute.

HTML attributes 在网页的代码中可以看到,DOM properties 是内存数据,在 HTML 代码中看不到。attr 操作的是 HTML attributes, prop 操作的是 DOM properties,它们可以是重叠的,例如 img 的 src 既可以使用 attr 访问,也可以使用 prop 访问,但是 checkbox 的 checked 应该使用 prop 访问,attr 访问会有奇怪的问题。大多数时候 attr 和 prop 的效果都一样,但是访问 boolean 的属性时切记要使用 prop。