如非说明,皆是使用1.5
本文只进行简单的代码提示,具体内容可自行百度
CXF
@Bean
public ServletRegistrationBean CXFServlet() {
ServletRegistrationBean cxfBean = new ServletRegistrationBean(new CXFServlet(), "/webservice/*");
cxfBean.setName("CXFServlet");
cxfBean.setLoadOnStartup(1);
return cxfBean;
}
@Configuration
public class CXFConfig {
@Autowired
private Bus bus;
@Autowired
private SSOService sSOService;
@Bean
public Endpoint endpointSSO() {
EndpointImpl endpoint = new EndpointImpl(bus, sSOService);
endpoint.publish("/sso");
return endpoint;
}
}
错误页面配置
/**
* 跳转至错误页面
* add 2018.07.11
* @author wm
* @param code
* @return
*/
@RequestMapping("/error/{code}")
public String goToErrorPage(@PathVariable(value="code") String code){
return code;
}
新增拦截器:
/**
* 错误页面拦截器
* 替代EmbeddedServletContainerCustomizer在war中不起作用的方法
* @author wm
*/
@Component
public class ErrorPageInterceptor extends HandlerInterceptorAdapter {
private List<Integer> errorCodeList = Arrays.asList(404,500);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws
Exception {
if (errorCodeList.contains(response.getStatus())) {
response.sendRedirect(request.getContextPath()+"/error/" + response.getStatus());
return false;
}
return super.preHandle(request, response, handler);
}
}
新增拦截配置:
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(errorPageInterceptor);//.addPathPatterns("/action/**", "/mine/**");默认所有
super.addInterceptors(registry);
}
兼容JSP
pom新增:
<dependencies>
...
<!--jsp支持 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- 配置jsp-jstl的支持 -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>jstl-api</artifactId>
<version>1.2</version>
</dependency>
...
</dependencies>
<build>
...
<resources>
<resource>
<directory>src/main/webapp</directory>
<!-- 处理jar包启动无法访问jsp的问题 -->
<targetPath>META-INF/resources</targetPath>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
</build>
新增配置类(处理jar包启动无法访问jsp的问题):
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import org.apache.catalina.Context;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.WebResourceRoot.ResourceSetType;
import org.springframework.util.ResourceUtils;
/**
* Add main class fat jar/exploded directory into tomcat ResourceSet.
*
* @author hengyunabc 2017-07-29
*
*/
public class StaticResourceConfigurer implements LifecycleListener {
private final Context context;
public StaticResourceConfigurer(Context context) {
this.context = context;
}
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) {
URL location = this.getClass().getProtectionDomain().getCodeSource().getLocation();
if (ResourceUtils.isFileURL(location)) {
// when run as exploded directory
String rootFile = location.getFile();
if (rootFile.endsWith("/BOOT-INF/classes/")) {
rootFile = rootFile.substring(0, rootFile.length() - "/BOOT-INF/classes/".length() + 1);
}
if (!new File(rootFile, "META-INF" + File.separator + "resources").isDirectory()) {
return;
}
try {
location = new File(rootFile).toURI().toURL();
} catch (MalformedURLException e) {
throw new IllegalStateException("Can not add tomcat resources", e);
}
}
String locationStr = location.toString();
if (locationStr.endsWith("/BOOT-INF/classes!/")) {
// when run as fat jar
locationStr = locationStr.substring(0, locationStr.length() - "/BOOT-INF/classes!/".length() + 1);
try {
location = new URL(locationStr);
} catch (MalformedURLException e) {
throw new IllegalStateException("Can not add tomcat resources", e);
}
}
this.context.getResources().createWebResourceSet(ResourceSetType.RESOURCE_JAR, "/", location,
"/META-INF/resources");
}
}
}
import org.apache.catalina.Context;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;
import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import cn.com.do1.component.config.assembly.StaticResourceConfigurer;
/**
* 处理jar包启动无法访问jsp的问题
* <p>Title: TomcatConfig</p>
* <p>Description: </p>
* @author wm
* @date 2018年7月24日
*/
@Configuration
@ConditionalOnProperty(name = "tomcat.staticResourceCustomizer.enabled", matchIfMissing = true)
public class TomcatConfig {
@Bean
public EmbeddedServletContainerCustomizer staticResourceCustomizer() {
return new EmbeddedServletContainerCustomizer() {
@Override
public void customize(ConfigurableEmbeddedServletContainer container) {
if (container instanceof TomcatEmbeddedServletContainerFactory) {
((TomcatEmbeddedServletContainerFactory) container)
.addContextCustomizers(new TomcatContextCustomizer() {
@Override
public void customize(Context context) {
context.addLifecycleListener(new StaticResourceConfigurer(context));
}
});
}
}
};
}
}
静态资源
方式一:
pom新增配置:
<resources>
<resource>
<directory>src/main/webapp</directory>
<!--注意此次必须要放在此目录下才能被访问到-->
<targetPath>META-INF/resources</targetPath>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
新增配置:
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/META-INF/resources/WEB-INF/js/");
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/META-INF/resources/WEB-INF/css/");
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/META-INF/resources/WEB-INF/images/");
registry.addResourceHandler("/common/**").addResourceLocations("classpath:/META-INF/resources/WEB-INF/common/");
registry.addResourceHandler("/register/**").addResourceLocations("classpath:/META-INF/resources/WEB-INF/register/");
registry.addResourceHandler("/plugin/**").addResourceLocations("classpath:/META-INF/resources/WEB-INF/plugin/");
super.addResourceHandlers(registry);
}
方式二(推荐):
将静态资源文件放到resouce/static目录下
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/js/**").addResourceLocations("classpath:/static/js/");
registry.addResourceHandler("/css/**").addResourceLocations("classpath:/static/css/");
registry.addResourceHandler("/images/**").addResourceLocations("classpath:/static/images/");
registry.addResourceHandler("/register/**").addResourceLocations("classpath:/static/register/");
registry.addResourceHandler("/plugin/**").addResourceLocations("classpath:/static/plugin/");
super.addResourceHandlers(registry);
}
文件上传
现象:上传文件返回异常java.lang.ClassCastException: org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile cannot be cast to org.springframework.web.multipart.commons.CommonsMultipartFile
原因:FileUtil中multipartToFile的代码片段 CommonsMultipartFile cf = (CommonsMultipartFile)multfile 与springboot自带的org.springframework.web.multipart.MultipartFile冲突
import org.springframework.web.multipart.commons.CommonsMultipartResolver;//这是旧项目引入的
import org.springframework.web.multipart.MultipartFile;//这是springboot整合的
解决:采用输入流方式获取File对象,具体代码自行百度
配置文件新增:
#upload
spring.http.multipart.enabled=true
spring.http.multipart.file-size-threshold=0 #0-ALLFILE
spring.http.multipart.location=D:/fsrzfw/temp
spring.http.multipart.max-file-size=10Mb
spring.http.multipart.max-request-size=10Mb
新增配置
/**
* 配置上传文件大小的配置
* @return
*/
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
// 单个数据大小
factory.setMaxFileSize("102400KB");
/// 总上传数据大小
factory.setMaxRequestSize("102400KB");
return factory.createMultipartConfig();
}
/**
* MultipartFile 转换成File
* update by wm 2018.07.12
* @param multfile 原文件类型
* @return File
* @throws IOException
*/
public static File multipartToFile(MultipartFile multfile) throws IOException {
//Springboot自带上传不支持CommonsMultipartFile
//CommonsMultipartFile cf = (CommonsMultipartFile)multfile;
//这个myfile是MultipartFile的
//DiskFileItem fi = (DiskFileItem) cf.getFileItem();
//return fi.getStoreLocation();
File f = null;
if ("".equals(multfile) || multfile.getSize() <= 0) {
multfile = null;
} else {
InputStream ins = multfile.getInputStream();
f = new File(multfile.getOriginalFilename());
StreamUtil.streamSaveAsFile(ins, f);
}
return f;
}
打JAR包运行
pom新增配置:
<build>
<finalName>fsrzfw</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>cn.com.do1.component.Application</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<dependencies>
<!-- spring热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
<version>1.2.6.RELEASE</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>ttf</nonFilteredFileExtension>
<nonFilteredFileExtension>woff</nonFilteredFileExtension>
<nonFilteredFileExtension>woff2</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/**</include>
</includes>
</resource>
<resource>
<directory>src/main/resource</directory>
<includes>
<include>**/**</include>
</includes>
</resource>
<resource>
<directory>src/main/webapp</directory>
<!-- 处理jar包启动无法访问jsp的问题 -->
<targetPath>META-INF/resources</targetPath>
<filtering>true</filtering>
<includes>
<include>**/**</include>
</includes>
</resource>
</resources>
</build>
Shiro 自定义 filter 匹配异常,无限拦截重定向
参考:Shiro 自定义 filter 匹配异常
原因:自定义Filter注册为了 Bean交给 Spring托管,它会被自动注册到 FilterChain中。请求先经过自定义Filter,导致请求被其先消费掉了,而ShiroFilter成了摆设。
解决:FUN1、利用 FilterRegistrationBean 注册自定义 Filter (建议使用)
ex:
@Bean
public CasFilter casFilter(){
CasFilter cf = new CasFilter();
cf.setSuccessUrl(successUrl);
cf.setFailureUrl(failureUrl);
return cf;
}
/**
* 注册casFilter
* @param casFilter
* @return
*/
@Bean
public FilterRegistrationBean registCasFilter(CasFilter casFilter) {
FilterRegistrationBean cas = new FilterRegistrationBean();
cas.setFilter(casFilter);
cas.setEnabled(false); //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理 x
return cas;
}
/**
* 注册shiroFilter
* @param securityManager
* @param casFilter
* @param logoutFilter
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager,
CasFilter casFilter,LogoutFilter logoutFilter) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
...
Map<String,Filter> filters = new HashMap<>();
filters.put("casFilter",casFilter);
filters.put("logoutFilter", logoutFilter);
shiroFilterFactoryBean.setFilters(filters); //添加casFilter到shiroFilter
...
}
FUN2、将 CasFilter注册为了 Bean交给 Spring托管,它会被自动注册到 FilterChain中,那我们如果不把它注册为 Bean就可以避免这个问题了。
ex:
/**
* 注册shiroFilter
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
...
Map<String,Filter> filters = new HashMap<>();
filters.put("casFilter",new CasFilter());
filters.put("logoutFilter", new LogoutFilter());
shiroFilterFactoryBean.setFilters(filters); //添加casFilter到shiroFilter
...
}
日志
现象:启动报错Caused by: java.lang.NoClassDefFoundError: ch/qos/logback/classic/turbo/TurboFilter
原因:springboot1.3.x和1.3.x以下版本才支持log4j的日志配置,1.3.x以上版本只支持log4j2和logback的日志配置
解决:使用log4j2或logback
jar包运行获取某个包下的class对象集合
现象:项目mvn install后jar包,启动报错,未获取到某个包下的class对象集合
原因:springboot项目打包后获取包资源所在路径与启动main不一样
ex://jarPaht:file:/E:/IDEABuilder/fs/tyrz-springboot/tyrz-front/target/fsrzfw.jar!/BOOT-INF/classes!/cn/com/do1/component/identitySource/service/impl
解决:逐一分割路径获取类对象
/**
* 获得包下面的所有的class
* @author FengHuayuan
* @date 2018年4月21日 下午12:25:20.
* @param pack
* @return
*/
public static List<Class<?>> getClassesFromPackage(String pack) {
List<Class<?>> clazzs = new ArrayList<Class<?>>();
// 是否循环搜索子包
boolean recursive = true;
// 包名字
String packageName = pack;
// 包名对应的路径名称
String packageDirName = packageName.replace('.', '/');
Enumeration<URL> dirs;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
String protocol = url.getProtocol();
if ("file".equals(protocol)) {
log.debug("*****【File类型】的扫描!");
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
findClassInPackageByFile(packageName, filePath, recursive, clazzs);
} else if ("jar".equals(protocol)) {
log.debug("*****【Jar类型】的扫描!");
String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
getClasssFromJarFile(filePath, clazzs);//wm add
}
}
} catch (Exception e) {
log.error(e.getMessage(),e);
}
return clazzs;
}
/**
* 从jar文件中读取指定目录下面的所有的class文件
* springboot打jar包专用
* @author wm
* @param jarPaht jar文件存放的位置
* @param filePaht 指定的文件目录
* @param clazzs 所有的的class的对象
*/
public static void getClasssFromJarFile(String jarPath,List<Class<?>> clazzs) {
log.info("getClasssFromJarFile - jarPath:"+jarPath);//wm
//jarPaht:file:/E:/IDEABuilder/fs/tyrz-springboot/tyrz-front/target/fsrzfw.jar!/BOOT-INF/classes!/cn/com/do1/component/identitySource/service/impl
String[] jarPaths = jarPath.split("!");
String jarPaht=jarPaths[0].substring(6);//去掉file:/
String startDir = (jarPaths[1]+jarPaths[2]).substring(1);//去掉/
JarFile jarFile = null;
try {
jarFile = new JarFile(jarPaht);
} catch (IOException e1) {
e1.printStackTrace();
}
List<JarEntry> jarEntryList = new ArrayList<JarEntry>();
Enumeration<JarEntry> ee = jarFile.entries();
while (ee.hasMoreElements()) {
JarEntry entry = (JarEntry) ee.nextElement();
if (entry.getName().startsWith(startDir) && entry.getName().endsWith(".class")) {
log.info("getClasssFromJarFile - entry:"+entry.getName());//wm
jarEntryList.add(entry);
}
}
for (JarEntry entry : jarEntryList) {
String className = entry.getName().replace('/', '.');
// BOOT-INF/classes/cn/com/do1/component/identitySource/service/impl/XXX.class
className = className.substring(17, className.length() - 6);//去掉 BOOT-INF/classes/ .class
try {
clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
诡异的异常
启动项目报错ClassNotFoundException: javax.ws.rs.core.Response$StatusType
解决:pom引入jsr311-api(g:javax.ws.rs)(a:jsr311-api)(v:1.1.1)