概述
性能调优准则
不要在没有必要的时候做性能调优
在大多数情况下,过早进行性能优化会占用大量时间,并使代码难以阅读和维护。更糟糕的是,这些优化通常不会带来任何好处,因为您花费大量时间来优化应用程序的非关键部分。
使用分析器来查找真正的瓶颈
- 为整个应用程序创建一个性能测试SuitCase
- 先进行最大的瓶颈上工作
- 使用StringBuilder来连接字符串
- 在一个语句中使用+连接字符串
- 尽可能使用基本数据
- 尽量避免使用BigInteger和BigDecimal
检查当前日志级别
正确的写法应该是这样的:
if (log.isDebugEnabled()) { log.debug(“User [” + userName + “] called method X with [” + i + “]”); }
使用Apache Commons的StringUtils.Replace来替代String.replace
- 缓存开销量较大的资源,如数据库连接等
编程进阶
阅读源代码
搞清楚以下4个问题:
A、源代码是要解决什么问题? B、源代码是通过什么原理实现? C、它采用了哪些接口、类? D、为什么采用这些接口和类?
多参与项目
通过项目的细节,你也可以查缺补漏,找到自己知识技能薄弱的环节。
问题指引你进阶之路
尽量以问题为导向,这可以让你的思考和理解聚焦,而不至于分散。
编程思想驾驭代码
可以边学边用《Effective Java》中的原理
Java程序员进阶书单
《Java编程思想》、《深入剖析Tomcat》、《深入理解Java虚拟机》、《JavaScript编程全解》、《Java程序性能优化》
Spring
Spring MVC
- 原理
配置阶段
引入
web.xml application.xml @Controller @Service @Autowired @RequestMapping @RequestParmter @ModelAndView
使用阶段
浏览器发送请求
doGet、doPost 根据url找对应的Method 通过反射调用和输出返回结果
手写mvc代码
提升对框架设计原理的理解
提高解决问题的效率
web.xml
添加servlet
引入application.properties文件 scanPackage=com.xxx.demo //扫描包路径下的所有类
添加与新建servlet对应的servlet-mapping
servlet对应的java类
继承J2EE自带的HttpServlet
public class DisptcherServlet extends HttpServlet { private Properties p = new Properties(); private List<String> classNames = new ArrayList<String>(); private Map<String,Object> ioc = new HashMap<String,Object>(); private Map<String,Method> handlerMapping = new HashMap<String,Method>();
protected void doGet(HttpServletRequest req, HttpServletResponse resp){
this.doGet(req, resp);
}
protected void doPost(HttpServletRequest req, HttpServletResponse resp){
doDispatch(req, resp);
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp){
String url = req.getRequestURI();
String contextPath = req.getContextPath();
url = url.replace(contextPath,"").replaceAll("/*","/");
if(!handlerMapping.containsKey(url)){
resp.getWriter().write("404 Not Found");
return;
}
Method method = handlerMapping.get(url);
//第一个参数:表示这个方法所在的实例
//!!!需要一个Handler内部类获取方法对应的类实例和方法需要的参数
//method.invoke();
}
@Override
public void init(ServletConfig config) throws ServletException{
// 1.加载配置文件application.properties
doLoadConfig(config.getInitParameter("contextConfigLocation"););
// 2.扫描所有相关类,拿到基础包路径,然后递归扫描
doScanner(p.getProperty("scanPackage"));
// 3.把扫描到的类实例化,放到ioc容器中(自己实现ioc容器,也就是一个Map,key是类名,value是类实例)
doInstance();
// 4.检查依赖注入,只要加了@Autowired注解的字段,不论公私有都要给强制赋值
doAutowired();
// 5.获取用户请求,根据所请求的url找到其对应的方法,通过反射机制,去调用
// HandlerMapping 把这一一个冠以存放到HandlerMapping中去(key是url,value是方法)
initHandlerMapping();
// 6.等待请求,把反射调用的结果通过response写出到浏览器中
do;
}
private void doLoadConfig(String path){
InputStream is = this.getClass().getClassLoader().getResourceAsStream(path);
p.load(is);
is.close();
}
private void doScanner(String packageName){
URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.","/"));
File dir = new File(url.getFile());
for(File file : dir.listFiles()){
if(file.isDirectory()){
doScanner(packageName + "." + file.getName());
}else{
classNames.add(packageName + "." + file.getName().replace(".class",""));
}
}
}
private void doInstance(){
if(classNames.isEmpty())return;
for(String className : classNames){
Class<?> clazz = Class.forName(className);
// 不是所有的类都要初始化的
if(class.isAnnotationPresent(Controller.class)){
//<bean id="" name="" class="">
String beanName = clazz.getSimpleName();
ioc.put(beanName, clazz.newInstance());
}else if(class.isAnnotationPresent(Service.class)){
//1.如果自己起了名字,则优先使用自己的名字进行匹配并注入
//2.默认首字母小写(发生在不是接口的情况)
//3.如果注入的类型是接口,要自动找到其实现类的实例并注入
Service service = clazz.getAnnotation(Service.class);
String beanName = service.value();//如果设了值,则不为""
if("".equals(beanName.trim())){
ioc.put(beanName, clazz.newInstance());
}else{
beanName = lowerFirst(clazz.getSimpleName()); // String首字母小写方法,自己实现
ioc.put(beanName, clazz.newInstance());
}
class<?> interfaces = clazz.getInterfaces();
for(Class<?> i : interfaces){
ioc.put(i.getName(), clazz.newInstance());
}
}
}
}
private void doAutowired(){
if(ioc.isEmpty()) return;
for(Entry<String,Object> entry:ioc.entrySet()){
Field[] fields = entry.getValue().getClass().getDeclaredFields();
for(Field field: fields){
if(!field.isAnnotationPresent(Autowired.class)continue;
//如果注解加了自定义名字
Autowired autowired = field.getAnnotation(Autowired.class);
String beanName = autowired.value().trim();
//通过声明接口注入
if("".equals(beanName.trim())){
beanName = field.getType.getName();
}
//只要加了Autowired注解的,强制赋值
field.setAccessible(true);
field.set(entry.getValue(),ioc.get(beanName));
}
}
}
private void initHandlerMapping(){
if(ioc.isEmpty())return;
for(Entry<String,Object> entry : ioc.entrySet()){
// 非常含有技术含量的点,要用反射调用方法
// 把所有的RequestMapping扫描出来,然后读取其值,和Method关联上,放入handlerMapping中
Class<?> clazz = entry.getValue().getClass();
//只和Controller有关
if(clazz.isAnnotationPresent(Controller.class)){
continue;
}
String baseUrl = "";
if(clazz.isAnnotationPresent(RequestMapping.class)){
RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
baseUrl = requestMapping.value();
}
Method[] methods = clazz.getMethods();
for(Method method:methods){
if(!method.isAnnotationPresent(RequestMapping.class)continue;
RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
String mappingUrl = "/" + baseUrl + "/" + requestMapping.value().replaceAll("/*","/");
handlerMapping.put(mappingUrl, method);
System.out.println("Mapping : " + mappingUrl + method);
}
}
}
}
添加注解类
Controller
package com.xxx.annotation; @Documented @Target(ElementType.TYPE)//在类上用 @Retention(TetentionPolicy.RUNTIME)// public @interface Controller { String value() default ""; }
RequestMapping
@Documented @Target({ElementType.TYPE,ElementType.METHOD})//在类上用,在方法上用 @Retention(TetentionPolicy.RUNTIME)// public @interface RequestMapping { String value() default ""; }
RequestParam
@Documented @Target({ElementType.PARAMETER)//在参数上用 @Retention(TetentionPolicy.RUNTIME)// public @interface RequestParam { String value() default ""; }
Service
@Documented @Target(ElementType.TYPE)//在类上用 @Retention(TetentionPolicy.RUNTIME)// public @interface Service { String value() default ""; }
Autowired
@Documented @Target(ElementType.RIELD)//在字段上用 @Retention(TetentionPolicy.RUNTIME)// public @interface Autowired { String value() default ""; }
使用注解
DemoService
@Service public class DemoService{ public String get(String name){ return name + "!!!!!!"; } }
DemoAction
@Controller @RequestMapping("/web") public class DemoAction{ @Autowired DemoService demoService; @RequestMapping("/get.json") public void get(HttpServletRequest req, HttpServletResponse resp, @RequestParam("name") String name){ String result = demoService.get(name); resp.getWriter().write(result); } }
启动服务,访问http://localhost:8080/web/get.json?name=john
spring-boot
spring-boot-starter-security模块默认密码
Boot会为你提供一个默认的用户账号user和默认角色USER,并且会在应用启动的时候在控制台上输出随机生成的密码。
spring-boot-actuator
提供更多面向生产环境的支持,安全,日志,管理,审计。
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>org.jolokia</groupId> <artifactId>jolokia-core</artifactId> </dependency> # MANAGEMENT HTTP SERVER (ManagementServerProperties) management.port= # defaults to 'server.port' management.address= # bind to a specific NIC management.context-path= # default to '/' management.add-application-context-header= # default to true management.security.enabled=true # enable security management.security.role=ADMIN # role required to access the management endpoint management.security.sessions=stateless # session creating policy to use (always, never, if_required, stateless) management.context-path=/actuator
spring-boot
1、下载eclipse mars
eclipse-jee-mars-R-win32-x86_64.zip
JDK1.8
3、运行,Goals
spring-boot:run4、断点调试,Profiles
-Drun.jvmArguments=”-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005”5、hateoas
Accept: application/json, application/xml
返回例子:
{"_embedded":{ "bookmarkResourceList":[ { "bookmark":{ "id":213, "uri":"http://bookmark.com/1/mpollack", "description":"A description" }, //整个系统中的所有其他 URI(包含所有会发生状态改变的)都是从分析这些表述中获得的 "_links":{ "bookmark-uri":{ "href":"http://bookmark.com/1/mpollack" }, "bookmarks":{ "href":"http://localhost:9008/mpollack/bookmarks" }, "self":{ "href":"http://localhost:9008/mpollack/bookmarks/213" } } }, { "bookmark":{ "id":214, "uri":"http://bookmark.com/2/mpollack", "description":"A description" }, "_links":{ "bookmark-uri":{ "href":"http://bookmark.com/2/mpollack" }, "bookmarks":{ "href":"http://localhost:9008/mpollack/bookmarks" }, "self":{ "href":"http://localhost:9008/mpollack/bookmarks/214" } } } ] }
}
为什么HATEOAS?
1)降低客户端编程错误。如下:访问uri全路径都返回了,直接使用即可,不用自己拼uri了"bookmarks":{ "href":"http://localhost:9008/mpollack/bookmarks" },
2)降低无效的状态迁移请求。只有当前状态下有效的状态变迁请求的URI会返回,其他无效的不会返回
3)渐进试改进并且不破坏(非必要的)旧客户端。服务器端严格控制后加的功能不破坏之前的行为,你可以合理快速的改进 API而不破坏所有客户端
6、Post模拟工具fiddler
spring boot 基础
aop
面向切面,提供切面注入的机制,通过这种方式,在业务运行中将定义好的切面通过切入点绑定到业务中,以实现将一些特殊的逻辑绑定到此业务中
aop名称
切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。 通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
使用spring AOP实现一个拦截器
http://blog.csdn.net/clementad/article/details/52035199
1、引入依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
2、创建拦截器类
/**
* 拦截器:记录用户操作日志,检查用户是否登录……
*/
@Aspect
@Component
public class ControllerInterceptor {
/**
* 定义拦截规则:拦截com.xjj.web.controller包下面的所有类中,有@RequestMapping注解的方法。
*/
@Pointcut("execution(* com.xjj.web.controller..*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
public void controllerMethodPointcut(){}
/**
* 拦截器具体实现
* @param pjp
* @return JsonResult(被拦截方法的执行结果,或需要登录的错误提示。)
*/
@Around("controllerMethodPointcut()") //指定拦截器规则;也可以直接把“execution(* com.xjj.........)”写进这里
public Object Interceptor(ProceedingJoinPoint pjp){
long beginTime = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod(); //获取被拦截的方法
String methodName = method.getName(); //获取被拦截的方法名
Set<Object> allParams = new LinkedHashSet<>(); //保存所有请求参数,用于输出到日志中
logger.info("请求开始,方法:{}", methodName);
Object result = null;
Object[] args = pjp.getArgs();
for(Object arg : args){
//logger.debug("arg: {}", arg);
if (arg instanceof Map<?, ?>) {
//提取方法中的MAP参数,用于记录进日志中
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) arg;
allParams.add(map);
}else if(arg instanceof HttpServletRequest){
HttpServletRequest request = (HttpServletRequest) arg;
result = new JsonResult(ResultCode.NOT_LOGIN, "该操作需要登录!去登录吗?\n\n(不知道登录账号?请联系老许。)", null);
//获取query string 或 posted form data参数
Map<String, String[]> paramMap = request.getParameterMap();
if(paramMap!=null && paramMap.size()>0){
allParams.add(paramMap);
}
}else if(arg instanceof HttpServletResponse){
//do nothing...
}else{
//allParams.add(arg);
}
}
try {
if(result == null){
// 一切正常的情况下,继续执行被拦截的方法
result = pjp.proceed();
}
} catch (Throwable e) {
logger.info("exception: ", e);
result = new JsonResult(ResultCode.EXCEPTION, "发生异常:"+e.getMessage());
}
if(result instanceof JsonResult){
long costMs = System.currentTimeMillis() - beginTime;
logger.info("{}请求结束,耗时:{}ms", methodName, costMs);
}
return result;
}
}
IOC(DI)
控制反转(IOC)和依赖注入(DI)的区别
http://blog.csdn.net/doris_crazy/article/details/18353197
(1)参与者都有谁: 一般有三方参与者,一个是某个对象;一个是IoC/DI的容器;另一个是某个对象的外部资源。 又要名词解释一下,某个对象指的就是任意的、普通的Java对象; IoC/DI的容器简单点说就是指用来实现IoC/DI功能的一个框架程序;对象的外部资源指的就是对象需要的,但是是从对象外部获取的,都统称资源,比如:对象需要的其它对象、或者是对象需要的文件资源等等。 (2)谁依赖于谁: 当然是某个对象依赖于IoC/DI的容器 (3)为什么需要依赖: 对象需要IoC/DI的容器来提供对象需要的外部资源 (4)谁注入于谁: 很明显是IoC/DI的容器 注入 某个对象 (5)到底注入什么: 就是注入某个对象所需要的外部资源 (6)谁控制谁: 当然是IoC/DI的容器来控制对象了 (7)控制什么: 主要是控制对象实例的创建 (8)为何叫反转: 反转是相对于正向而言的,那么什么算是正向的呢?考虑一下常规情况下的应用程序,如果要在A里面使用C,你会怎么做呢?当然是直接去创建C的对象,也就是说,是在A类中主动去获取所需要的外部资源C,这种情况被称为正向的。那么什么是反向呢?就是A类不再主动去获取C,而是被动等待,等待IoC/DI的容器获取一个C的实例,然后反向的注入到A类中。 依赖注入和控制反转是对同一件事情的不同描述,从某个方面讲,就是它们描述的角度不同。 依赖注入是从应用程序的角度在描述,可以把依赖注入描述完整点:应用程序依赖容器创建并注入它所需要的外部资源; 而控制反转是从容器的角度在描述,描述完整点:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源。
反射
程序运行状态时,对于任意一个类,都能够知道这个类的所有属性和方法(包括私有),对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态类型信息及动态调用对象方法的功能叫做反射机制;
http://blog.csdn.net/it_man/article/details/4402245
通常,每个对象在使用他的合作对象时,自己均要使用像new object() 这样的语法来完成合作对象的申请工作。你会发现:对象间的耦合度高了。而IOC的思想是:Spring容器来实现这些相互依赖对象的创建、协调工作。
比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。
依赖注入的思想也很简单,它是通过反射机制实现的,在实例化一个类时,它通过反射调用类中set方法将事先保存在HashMap中的类属性注入到类中。
首先实例化一个类 public static Object newInstance(String className) { Class<?> cls = null; Object obj = null; try { cls = Class.forName(className); obj = cls.newInstance(); } catch (Exception e) { throw new RuntimeException(e); } return obj; } 接着它将这个类的依赖注入进去 public static void setProperty(Object obj, String name, String value) { Class<? extends Object> clazz = obj.getClass(); try { String methodName = returnSetMthodName(name); Method[] ms = clazz.getMethods(); for (Method m : ms) { if (m.getName().equals(methodName)) { if (m.getParameterTypes().length == 1) { Class<?> clazzParameterType = m.getParameterTypes()[0]; setFieldValue(clazzParameterType.getName(), value, m, obj); break; } } } } catch (Exception e) { throw new RuntimeException(e); } } 最后它将这个类的实例返回给我们,我们就可以用了。
实战
spring boot 性能优化
http://blog.oneapm.com/apm-tech/385.html
组件自动扫描带来的问题
有三方面的影响:
1、会导致项目启动时间变长。当启动一个大的应用程序,或将做大量的集成测试启动应用程序时,影响会特别明显。 2、会加载一些不需要的多余的实例(beans)。 3、会增加 CPU 消耗。
解决方案:
移除 @SpringBootApplication 和 @ComponentScan 两个注解来禁用组件自动扫描 然后在我们需要的 bean 上进行显式配置: @Configuration @EnableAutoConfiguration public class SampleWebUiApplication { // ... // 用 @Bean 注解显式配置,以便被 Spring 扫描到 @Bean public MessageController messageController(MessageRepository messageRepository) { return new MessageController(messageRepository); }
避免组件自动扫描带来的问题
首先要知道我们需要的组件列表是哪些,可以用 -Ddebug 的方式来帮助我们明确地定位:
mvn spring-boot:run -Ddebug … ========================= AUTO-CONFIGURATION REPORT ========================= Positive matches: ----------------- DispatcherServletAutoConfiguration - @ConditionalOnClass classes found: org.springframework.web.servlet.DispatcherServlet (OnClassCondition) - found web application StandardServletEnvironment (OnWebApplicationCondition) ...
拷贝 Positive matches 中列出的信息:
DispatcherServletAutoConfiguration EmbeddedServletContainerAutoConfiguration ErrorMvcAutoConfiguration HttpEncodingAutoConfiguration HttpMessageConvertersAutoConfiguration JacksonAutoConfiguration JmxAutoConfiguration
更新项目配置,显式地引入这些组件,引入之后,再运行一下应用确保没有错误发生:
@Configuration @Import({ DispatcherServletAutoConfiguration.class, EmbeddedServletContainerAutoConfiguration.class, ErrorMvcAutoConfiguration.class, HttpEncodingAutoConfiguration.class, HttpMessageConvertersAutoConfiguration.class, }) public class SampleWebUiApplication {
不需要 JMX 和 WebSocket 功能,我就删掉了它们。
将Servlet容器变成Undertow
从依赖信息里移除 Tomcat 配置:
<exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions>
然后添加 Undertow:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>
spring boot 远程调试
-Xdebug -Xrunjdwp:server=y,transport=dt_socket,address=8000,suspend=n
spring boot 打war包后
application.properties 配置文件需要放到war包的同一目录下,否则报Db配置错误。
thymeleaf里面的th和spring security结合进行页面权限配置
<li th:if="${#authorization.expression('!isAuthenticated()')}">
<a href="#" data-toggle="modal"
data-target="#changePasswordModal">修改密码</a>
</li>
spring 集成 h2数据库
application.properties
增加配置
#./database 表示当前启动目录下的database数据库,文件为database.mv.db文件 spring.datasource.url=jdbc:h2:file:./database;AUTO_SERVER=TRUE;DB_CLOSE_DELAY=-1 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true spring.jpa.hibernate.naming-strategy=org.hibernate.cfg.EJB3NamingStrategy spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect
maven 配置
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com</groupId> <artifactId>lottery</artifactId> <version>1.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.2.5.RELEASE</version> </parent> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> </dependencies> <properties> <java.version>1.7</java.version> </properties> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
h2默认生成的表varchar是255长度
需要手工建立表
CREATE CACHED TABLE PUBLIC.TODAYINFO( ID BIGINT NOT NULL auto_increment, DATES VARCHAR(255) NOT NULL , FOCURS VARCHAR(5000), FUNDL VARCHAR(5000), SOIL VARCHAR(5000), SOILADVICE VARCHAR(5000), SSILVER VARCHAR(5000), SSILVERADVICE VARCHAR(5000), TECL VARCHAR(5000), UPDATETIME VARCHAR(255) )
使用工具:H2 Database Engine 1.4.185 绿色版
JpaRepository
public interface TodayInfoRepository extends JpaRepository<TodayInfo, Long> { @Query("SELECT o FROM TodayInfo o") Page<TodayInfo> getPage(Pageable page); @Query(nativeQuery = true, value = "SELECT a.* FROM `TodayInfo` a WHERE a.`dates` = :dates LIMIT 1") TodayInfo getUniqueByDates(@Param("dates") String dates); }
service
PageRequest pageRequest = new PageRequest(currPage, pageSize, Sort.Direction.DESC, "dates"); Page<TodayInfo> pages = todayInfoRepository.getPage(pageRequest);
杂记
加载到配置文件,给入口类添加@ImportResource(“applicationContext.xml”)
spring security 官方文档
http://docs.spring.io/spring-security/site/docs/3.2.8.RELEASE/reference/htmlsingle/
Druid
https://github.com/alibaba/druid
Druid 是阿里唯一使用的数据库连接池,支持双十一等最严苛的使用场景。是“为监控而生的数据库连接池”
- 简介
https://www.cnblogs.com/niejunlei/p/5977895.html
Druid是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。
maven中央仓库: http://central.maven.org/maven2/com/alibaba/druid/
配置maven
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>${druid-version}</version>
</dependency>
Dubbo2
https://github.com/alibaba/dubbo
dubbo是一个分布式的服务架构,可直接用于生产环境作为SOA服务框架。
实战
Eclipse添加阿里巴巴Java开发规约插件
http://blog.csdn.net/jiliang272/article/details/78269600
java 代码库
获取访问者IP
/** * 获取访问者IP * * 在一般情况下使用Request.getRemoteAddr()即可,但是经过nginx等反向代理软件后,这个方法会失效。 * * 本方法先从Header中获取X-Real-IP,如果不存在再从X-Forwarded-For获得第一个IP(用,分割), * 如果还不存在则调用Request .getRemoteAddr()。 * * @param request * @return */ public static String getIpAddr(HttpServletRequest request) throws Exception{ String ip = request.getHeader("X-Real-IP"); if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { return ip; } ip = request.getHeader("X-Forwarded-For"); if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) { // 多次反向代理后会有多个IP值,第一个为真实IP。 int index = ip.indexOf(','); if (index != -1) { return ip.substring(0, index); } else { return ip; } } else { return request.getRemoteAddr(); } }
Unicode转UTF-8代码
String str="\u7528\u6237\u540d\u6216\u5bc6\u7801\u4e0d\u6b63\u786e\uff0c\u8bf7\u91cd\u8bd5"; System.out.println(decodeUnicode(str)); private static String decodeUnicode(String theString) { char aChar; int len = theString.length(); StringBuffer outBuffer = new StringBuffer(len); for (int x = 0; x < len;) { aChar = theString.charAt(x++); if (aChar == '\\') { aChar = theString.charAt(x++); if (aChar == 'u') { // Read the xxxx int value = 0; for (int i = 0; i < 4; i++) { aChar = theString.charAt(x++); switch (aChar) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': value = (value << 4) + aChar - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': value = (value << 4) + 10 + aChar - 'a'; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': value = (value << 4) + 10 + aChar - 'A'; break; default: throw new IllegalArgumentException( "Malformed \\uxxxx encoding."); } } outBuffer.append((char) value); } else { if (aChar == 't') aChar = '\t'; else if (aChar == 'r') aChar = '\r'; else if (aChar == 'n') aChar = '\n'; else if (aChar == 'f') aChar = '\f'; outBuffer.append(aChar); } } else outBuffer.append(aChar); } return outBuffer.toString(); }
问题汇总
mp4视频在html里,ios设备浏览器、微信等无法播放视频问题
不能用spring-boot来当容器启动服务,需要单独html,直接放到tomcat中,不用spring-boot项目
<video id="video" style="position: absolute; left: 63.3%;" controls="controls" poster="resources/images/H5-2.jpg"> <source src="resources/video/meidui3.mp4" type='video/mp4;' /> </video>
关于在打包Jar文件时遇到的资源路径问题
http://www.cnblogs.com/fjdingsd/p/4680922.html
如果将资源同代码一起打包进Jar包中,当程序打包成可执行Jar包时
URL picUrl = this.getClass().getResource("/palette.gif"); Image image = new ImageIcon(picUrl).getImage();
如果资源路径前没有加“/”,则无论怎么点Jar包都不会有反应。
java代码写的中文(非从数据库读的中文)返回给客户端变乱码问题。
maven配置文件里要设置成用utf-8编译java代码
<plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>tomcat-maven-plugin</artifactId> <version>1.0</version> <configuration> <!-- 这里就是所要配置的 端口号 --> <port>9109</port> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.8</source> <target>1.8</target> <encoding>utf8</encoding> </configuration> </plugin> </plugins>
a