src/main/resources/sql
中;application-dev.yml
中数据库账号密码是否正确;EasyWebApplication.java
运行项目:byte[] bytes = new byte[in.available()];
in.read(bytes);
String base64 = Base64.getEncoder().encodeToString(bytes);
System.out.println("data:image/png;base64," + base64); // 带上头部// base64转为图片
String base64 = "data:image/png;base64,iVBORw0KAYAAABzenr0AAAAvABJRU5ErkJggg==";
String base64Str = base64.substring(base64.indexOf(";") + 8); // 去掉头部
byte[] bytes = Base64.getDecoder().decode(base64Str.getBytes());
String suffix = base64.substring(11, base64.indexOf(";")); // 获取文件后缀
FileOutputStream out = new FileOutputStream(new File("C:/a." + suffix));
out.write(bytes);
框架已经内置了FileController支持上传、预览、下载、缩略图、office预览等功能。
接口 | 参数 | 方法 | 说明 |
---|---|---|---|
file/upload | file | post | 上传文件 |
file/upload/base64 | base64 | post | 上传Base64文件 |
file/{dir}/{name} | 无 | get | 预览文件(支持office) |
file/thumbnail/{dir}/{name} | 无 | get | 预览缩略图 |
file/download/{dir}/{name} | 无 | get | 下载文件 |
file/list | dir | get | 查询文件列表 |
file/remove | path | delete | 删除文件 |
前端使用示例:
上传成功返回的json数据示例,fileName是文件原始名称:
{"code":0,"msg":"上传成功","url":"20200611/QQ截图20200611105349(1).png","location":"http://192.168.1.126:8081/api/file/20200611/QQ截图20200611105349(1).png","fileName":"QQ截图20200611105349.png","dir":"/20200611"
}
base64形式:
$.post('file/upload/base64', {base64: 'data:image/png;base64,xJsfek3hJHSfejhj6sdakjed=='
}, function(res){console.log(res); // 返回结果同上,没有fileName字段
});
预览、缩略图、下载文件:
// 预览文件,支持office文件预览
window.open('file/20191230/xxx.jpg');// 查看缩略图
window.open('file/thumbnail/20191230/xxx.jpg');// 下载原文件
window.open('file/download/20191230/xxx.jpg');
支持office预览需要服务器安装OpenOffice,然后在Constants.java
中配置安装位置,也可在群里下载。
异步任务需要在Application上面加@EnableAsync
注解开启,框架已经加了:
@EnableAsync
@SpringBootApplication
public class EasyWebApplication {public static void main(String[] args) {SpringApplication.run(EasyWebApplication.class, args);}
}
在你需要异步执行的方法上面加@Async
注解:
@Service
public class Test {@Asyncpublic void doTask() {Thread.sleep(10000);System.out.println("任务完成,耗时10s");}
}
框架里面的登录日志、操作日记添加都是使用的异步任务,异步任务一般用于跟业务逻辑无关的操作, 使业务流程处理完后立即返回给前端,与业务流程无关的操作异步执行,提升业务功能的执行效率。
定时任务需要在Application上面加@EnableScheduling
注解开启:
@EnableScheduling
@SpringBootApplication
public class EasyWebApplication {public static void main(String[] args) {SpringApplication.run(EasyWebApplication.class, args);}
}
在需要定时执行的方法上面加@Scheduled
注解:
@Service
public class Test {@Scheduled(cron="*/5 * * * * *")public void reportCurrentTime() {System.out.println(new Date());}
}
相关链接:在线Cron表达式生成器
EmailService中已经封装了三个通用的发邮件的方法:
方法 | 说明 |
---|---|
sendTextEmail(String title, String content, String[] toEmails) | 发送普通文本邮件 |
sendFullTextEmail(String title, String html, String[] toEmails) | 发送富文本邮件 |
sendHtmlEmail(String title, String tpl, Map map, String[] toEmails) | 发送html模板邮件 |
使用方法:
public class Test {@Autowiredprivate EmailService emailService;public void test() throws MessagingException, IOException {// 发送纯文本邮件,参数三是收件人emailService.sendTextEmail("邮件标题", "邮件内容", new String[]{"xxx@qq.com"});// 发送富文本邮件emailService.sendFullTextEmail("邮件标题", "邮件内容", new String[]{"xxx@qq.com"});// 发送模板邮件Map
}
html模板放在templates下面,使用beetl模板语法:
账号: ${name!} 性别: ${sex!}
EmailService使用前需要确保配置正确,检查application.properties中的配置:
spring.mail.host=smtp.qq.com
# 这里改成你的邮箱
spring.mail.username=xxxxx@foxmail.com
# 这里改成你的密码
spring.mail.password=xxxxxxxxxx
spring.mail.default-encoding=UTF-8
## 使用25端口认证
#spring.mail.port=25
#spring.mail.properties.mail.smtp.auth=true
#spring.mail.properties.mail.smtp.starttls.enable=true
#spring.mail.properties.mail.smtp.starttls.required=true
## 使用465端口SSl认证
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.smtp.socketFactory.port=465
这里的密码不是登录密码,获取方式以QQ邮箱为例,进入“设置/账户”:
找到“POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务”:
点击“开启”就会弹出密码,properties文件中25端口和465端口配置一个即可,一般服务器25端口是封闭的,建议使用465端口。
application.yml
是SpringBoot的核心配置文件,所有的配置都在它里面,另外还有三个是做多环境配置的:
配置文件 | 说明 |
---|---|
application-dev.yml | 开发环境配置,配置开发环境的数据源、日志处理等 |
application-prod.yml | 生成环境配置,配置生产环境的数据源、日志处理等 |
application-test.yml | 测试环境配置,配置测试环境的数据源、日志处理等 |
在application.yml中配置spring.profiles.active=dev
来指定使用哪个环境,建议像数据库、redis、日志处理等 在不同环境中配置不一样的写在三个不同环境的配置文件中,不会随着环境改变的配置写在application.yml中。
日期类型转换器位于com.xxx.common.core.config.DateConverterConfig.java
,如果对象有Date类型的字段,对象在Controller中 作为参数接收时会将前端传递的string格式转成Date格式,前端直接传递如下几种格式的字符串,会自动转换成Date类型:
yyyy-MM-dd
yyyy-MM-dd HH:mm
yyyy-MM-dd HH:mm:ss
注意: 只会转成Date类型,如果对象里面用的是LocalTime类型是不支持的
全局异常处理器位于com.xxx.common.core.exception.GlobalExceptionHandler.java
,在代码的任何位置都可以抛出异常, 异常信息不会直接到达页面,会跳转到错误页面,如果是ajax请求,会返回json数据:
{"code": 500, "msg": "系统错误", "error": "java.lang.NullPointerException..."}
自定义异常:
异常类 | 说明 |
---|---|
BusinessException | 业务异常,默认错误码500,错误信息“系统错误” |
ParameterException | 参数异常,默认错误码400,错误信息“参数错误” |
有时候异常是需要抛出的,而不是捕获,尤其是Service层,因为抛出异常才可以做事物回滚,例如:
public class UserServiceImpl {@Transactional(rollbackFor = Exception.class)public boolean addUser(User user, List
上面是一个添加用户的例子,添加完用户后还要添加用户的角色,如果角色添加失败,应该回滚添加的用户,此时抛出异常才可回滚, 也别忘了加@Transactional
注解。
使用场景二:
public class UserServiceImpl {public boolean addUser(User user) {if (baseMapper.selectByUsername(user.getUsername()) != null) {throw new BusinessException("账号已经存在");}return baseMapper.insert(user) > 0;}
}
上面仍然是一个添加用户的例子,添加用户之前要判断账号是否存在,但service返回的是boolean的类型,直接返回false错误信息不明确, 如果在controller里判断,每个调用service的controller都要判断,此时可以用自定义的BusinessException抛出异常, 经过异常处理器的处理之后,前端收到的json仍然是:{"code": 500, "msg": "账号已经存在"}
,简单方便。
自定义异常的使用:
throw new BusinessException("账号已经存在");
throw new BusinessException(500, "账号已经存在"); // 重写code,默认是500throw new ParameterException("参数不能为空");
throw new ParameterException(400, "参数不能为空"); // 重写code,默认是400
BusinessException和ParameterException都继承IException,因为Exception没有code这个字段,只有message字段, IException增加了code字段,所以要自定义其他类型的异常,最好也继承IException。
MybatisPlus的配置位于com.xxx.common.core.config
下面,代码如下:
@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {// 分页插件@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor().setLimit(1000);}
}
@EnableTransactionManagement
注解是开启事务,这里加了就不用在Application上加了。
SpringSecurity框架的配置位于com.xxx.common.core.config.SecurityConfig.java
:
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers(HttpMethod.GET, "/", "/assets/**", "/**.html", "/file/**").permitAll().antMatchers("/login", "/error", "/druid/**", "/swagger-ui.html","/swagger-resources/**", "/webjars/**", "/v2/api-docs").permitAll().anyRequest().authenticated().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().headers().frameOptions().sameOrigin().and().cors().and().csrf().disable();http.exceptionHandling().accessDeniedHandler(jwtExceptionHandler()).authenticationEntryPoint(jwtExceptionHandler());http.logout().logoutUrl("/logout").logoutSuccessHandler(jwtLogoutSuccessHandler());http.addFilterBefore(jwtLoginFilter(), UsernamePasswordAuthenticationFilter.class);http.addFilterBefore(jwtRequestFilter(), UsernamePasswordAuthenticationFilter.class);}
}
permitAll()
代表排除拦截,authenticated()
代表需要登录后访问。
SpringSecurity相关的其他配置类:
配置文件 | 说明 |
---|---|
JwtLoginFilter.java | 登录过滤器,处理登录请求成功和失败 |
JwtRequestFilter.java | 请求过滤器,处理携带token的请求 |
JwtLogoutSuccessHandler.java | 处理退出登录成功的操作 |
JwtExceptionHandler.java | 处理没有权限的异常 |
UserDetailsServiceImpl.java | 用于登录查询用户和权限 |
JwtLoginFilter登录过滤器:
这个类主要是处理登录接口,在登录成功后签发token并返回json数据给前端,在登录失败后 记录登录日志并返回json数据给前端:
public class JwtLoginFilter extends UsernamePasswordAuthenticationFilter {@Autowiredprivate LoginRecordService loginRecordService;public JwtLoginFilter(AuthenticationManager authenticationManager) {super.setAuthenticationManager(authenticationManager);}/** 登录成功签发token返回json数据 */@Overrideprotected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)throws IOException, ServletException {UserDetails user = (UserDetails) authResult.getPrincipal();String access_token = JwtUtil.buildToken(user.getUsername(), Constants.TOKEN_EXPIRE_TIME, Constants.TOKEN_KEY);// 记录登录日志loginRecordService.saveAsync(user.getUsername(), request);// 返回json数据response.setContentType("application/json;charset=UTF-8");PrintWriter out = response.getWriter();out.write(JSON.toJSONString(JsonResult.ok("登录成功").put("access_token", access_token).put("token_type", JwtUtil.TOKEN_TYPE)));out.flush();}/** 登录失败处理 */@Overrideprotected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {String username = request.getParameter("username");response.setContentType("application/json;charset=UTF-8");PrintWriter out = response.getWriter();JsonResult result;if (e instanceof UsernameNotFoundException) {result = JsonResult.error("账号不存在");loginRecordService.saveAsync(username, LoginRecord.TYPE_ERROR, "账号不存在", request);} else if (e instanceof BadCredentialsException) {result = JsonResult.error("账号或密码错误");loginRecordService.saveAsync(username, LoginRecord.TYPE_ERROR, "账号或密码错误", request);} else if (e instanceof LockedException) {result = JsonResult.error("账号被锁定");loginRecordService.saveAsync(username, LoginRecord.TYPE_ERROR, "账号被锁定", request);} else {result = JsonResult.error(e.getMessage());}out.write(JSON.toJSONString(result));out.flush();}
}
登录接口调用形式:
$.post('/login', {username: 'admin',password: '123456'
},function(res){console.log(res);
});
登录成功返回的json格式为:
{"code": 0, "msg": "登录成功", "access_token": "xxxxxxxxxxxxxxxx", "token_type": "Bearer"}
JwtRequestFilter请求过滤器:
这个类主要是处理所有携带token的请求,从request中获取前端传递的token,并验证token,然后把token对应的User设置到Security中:
public class JwtRequestFilter extends OncePerRequestFilter {private UserDetailsService userDetailsService;public JwtRequestFilter(UserDetailsService userDetailsService) {this.userDetailsService = userDetailsService;}@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throws ServletException, IOException {String access_token = JwtUtil.getAccessToken(request);if (access_token != null) {try {Claims claims = JwtUtil.parseToken(access_token, Constants.TOKEN_KEY);String username = claims.getSubject();UserDetails userDetails = userDetailsService.loadUserByUsername(username);UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authentication);// token将要过期签发新token, 防止突然退出登录if ((claims.getExpiration().getTime() - new Date().getTime()) / 1000 / 60
如果token即将过期生成新的token并设置在response的header中,防止用户正在操作的情况需要退出重新登录,所以前端在每次请求完成后 应该判断response的header中是否有Authorization
,有应该保存新的token。
前端请求接口传递token的形式:
// 在参数中传递token
$.get('/sys/user', {access_token: 'xxxxx'
}, function(res){console.log(res);
}, 'json');// 在header中传递token
$.ajax({url: '/sys/user', headers: { Authorization: 'Bearer ' + token },success: function(res){console.log(res);}
});
在参数中传递用access_token
,在header中传递用Authorization
,值前面要加Bearer
,注意有个空格。
security权限注解使用:
// 一般加在controller的方法上面
@PreAuthorize("hasAuthority('sys:user:save')")
Swagger配置类位于com.xxx.common.core.config.Swagger2Config.java
,Swagger的配置很简单,基本打开看看就明白了, 需要注意的是加了一个可以在yml中配置的参数swagger.host
用来配置生产环境的接口地址(域名等)。
比如你打包部署到线上并绑定了域名可以这样配置以保证swagger文档的在线接口测试功能可以正常访问:
java -jar easyweb-security.jar --swagger.host=easyweb.vip
// 或者
java -jar easyweb-security.jar --swagger.host=192.168.1.245:8081
swagger接口文档如何正确使用,访问ip:端口/swagger-ui.html
进入文档后,先找到登录接口输入账号密码执行后获取token, 然后在文档的右上角点击Authorize
按钮,在弹出窗的输入框里面输入Bearer 登录返回的token
点击Authorize
按钮, 然后执行文档上面的所有接口都会自动带上token了。
resources下的static
目录用于存放静态资源,因为是前后端分离的,所以不需要templates
目录,static下面的文件可以直接放到nginx中分离部署, 之所以放在static下面是为了一个人开发的方便,如果有专门的前端完全可以把static下面的文件单独作为一个前端项目,分离开发、分离部署。
在pom.xml中增加:
在application.properties中配置
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
项目生成器可以生成一个完整的项目,包括controller、service、entity、mapper、页面等,生成的功能包含添加、修改、删除、批量添加、批量修改、 批量删除、查询全部、分页查询、根据id查询,项目生成器可以自定义模板,目前提供了shiro版本的框架模板以及SpringSecurity版本的框架模板, 也可以自己制作框架模板。
项目生成器使用步骤,首先你要创建好你的数据库,数据库的字符集选utf8mb4
,排序规则选utf8mb4_general_ci
, 然后导入系统管理部分的sql脚本:
创建好数据库后再创建你的业务表,这里新增了两个表举例子,文章和评论,注意表备注后面不要带表,不然生成后的代码就是文章表管理了:
第一步配置你的数据库连接信息:
第二步选择你的表,功能比较少的项目可以不划分模块,模块名空着:
第三步配置其它信息:
配置完后点击立即生成,生成完毕会自动下载,解压下载的压缩包:
用IDEA开发工具导入项目,生成的项目结构如下:
在resources\sql\
目录下会有一个生成的sql脚本,是用来添加菜单和角色菜单的,你可以适当修改后导入数据库, 也可以直接导入到数据库中:
对于功能较多的项目,数据表较多的项目推荐把不同的表划分到不同的模块中,这里的模块最后生成的不是maven的多模块, 是以划分包的形式,你可以根据自己业务进行划分:
划分多模块最后生成的项目结构为:
生成好的项目可以直接运行,添删改查、批量添、改、删、分页查、根据id查、页面都会生成:
生成的代码没有多表关联的操作,但是提供好了模板,你可以看到生成的Controller中关联的操作注释了:
/** 评论管理 */
@Controller
@RequestMapping("/model2/comment")
public class CommentController extends BaseController {@Autowiredprivate CommentService commentService;/** 分页查询评论 */@ResponseBody@RequestMapping("/page")public PageResult
}
如果需要多表关联查询,把注释的代码放开,service不用修改,需要在mapper.xml
中增加关联的sql语句,模板会生成好sql语句, 你只需要在原来的语句上面增加LEFT JOIN
语句去关联表即可:
上面的例子就是在评论表中把对应文章的标题title关联查询出来,你还需要在实体类中增加title字段:
/** 评论 */
@TableName("tb_comment")
public class Comment implements Serializable {private static final long serialVersiOnUID= 1L;/** 评论id */@TableId(value = "comment_id", type = IdType.AUTO)private Integer commentId;/** 评论人 */private String userName;//......省略/** 修改时间 */private Date updateTime;/** 文章标题 */@TableField(exist = false)private String title;
}
增加关联的字段并加@TableField(exist = false)
注解,然后Controller中查询全部、分页查询、根据id查询 这三个方法返回的json数据里面就会有这个关联的字段了。
一套完整的模板应该包含:
名称 | 类型 | 说明 |
---|---|---|
project | 目录 | 项目的框架 |
config.json | 文件 | 对于框架的配置 |
controller.java.btl | 文件 | controller生成模板 |
entity.java.btl | 文件 | 实体类生成模板 |
mapper.java.btl | 文件 | mapper生成模板 |
mapper.xml.btl | 文件 | mapper的xml生成模板 |
service.java.btl | 文件 | service生成模板 |
serviceImpl.java.btl | 文件 | serviceImpl生成模板 |
generator.sql.btl | 文件 | sql脚本生成模板 |
page.html.btl | 文件 | 页面生成模板 |
最后一个page.html.btl
是非必须的,而且名字、个数等可以在config.json中配置,除此之外,其它文件都是是必须要有的。
project这个名字是固定的不能修改,里面放的是基础框架的源码:
config.json说明:
{"packageName": "com.egao","pages": [{"tpl": "page.html.btl","output": "resources/templates/"}],"replaces": [{"files": ["src/main/resources/application-dev.yml","src/main/resources/application-prod.yml"],"items": [{"orgStr": "username: root","newStr": "username: ${dbUserName}"},{"orgStr": "password: 123456","newStr": "password: ${dbPassword}"},{"orgStr": "driver-class-name: com.mysql.cj.jdbc.Driver","newStr": "driver-class-name: ${dbDriverName}"}]},{"files": ["src/main/resources/application.yml"],"items": [{"orgStr": "aop-patterns: com.egao.*.*.service.*","newStr": "aop-patterns: ${groupId}.*.*.service.*"},{"orgStr": "typeAliasesPackage: com.egao.**.entity","newStr": "typeAliasesPackage: ${groupId}.**.entity"}]}]
}
config.json可以配置三个属性:
pages: []
pages
是一个数组,可以配置多个,tpl
是模板的名称,output
是模板输出位置。
replaces
也是一个数组,里面的files
是需要修改基础框架的文件,items
是需要修改的内容, orgStr
是需要修改的原始内容,newStr
是替换的内容,newStr
可以使用${}
语法获取一些模板数据。
newStr
可以获取的数据:
数据 | 描述 |
---|---|
projectName | 生成的项目名称 |
groupId | 生成的项目的groupId |
groupIdPath | groupId的点变成斜杠形式 |
packageName | 生成的项目的包名 |
packageNamePath | 包名的点变成斜杠形式 |
author | 作者的名称 |
dbUrl | 数据库的url |
dbUserName | 数据库的账号 |
dbPassword | 数据库的密码 |
dbDriverName | 数据库的驱动名 |
其他模板可以取的数据:
制作好的模板压缩并上传到项目生成器中就可以使用了:
提示 如果上传失败请自己把压缩包放在C:\easyweb-generator\tpl
目录下面
deleted
表
create_time
(模板会对表单过滤此字段)update_time
(模板会对表单过滤此字段)当然你可以修改项目生成器源码满足更多的配置。
代码示例:
完整代码:
建议表单内上传文件像上面这样,先上传获取url,提交表单时只是把上传后的url提交,而不是传统的表单提交又有文件、 又有其他参数,当然这样做会存在文件上传了,表单不提交导致的垃圾文件的问题,这个问题可以通过定时清理很久没有使用的文件来解决。
在setter.js的ajaxSuccessBefore中判断服务器的response的header中是否有Authorization
字段,有就表示token马上要过期了, 服务端生成了新的token,前端需要把新的token存起来:
layui.define(['table'], function (exports) {var setter = {/* ajax请求结束后的处理 */ajaxSuccessBefore: function (res, url, obj) {// 判断response是否有tokenvar newToken = obj.xhr.getResponseHeader('Authorization');if (newToken) setter.putToken({access_token: newToken});// ......其他代码省略return true;}};exports('setter', setter);
});
或者使用ajaxSetup实现,这个对table的请求也有用:
// ajax统一处理
$.ajaxSetup({complete: function (xhr) {var newToken = xhr.getResponseHeader('Authorization');if (newToken) setter.putToken({access_token: newToken});}
});
点击右侧的Maven/package即可开始打包,打好的包在target下面:
先把jar包上传到linux里面,建议一个项目(jar包)建一个文件夹,然后通过如下命令启动:
nohup java -jar easyweb-shiro-0.0.1.jar --spring.profiles.active=prod
命令执行后直接关闭此窗口,不要用Ctrl+C停止
如果要实时查看打印信息,使用如下命令:
tail -f nohup.out
关闭项目使用如下命令:
# 查看端口号的进程id
netstat -anp |grep 8083# 显示如下信息
tcp 0 0 0.0.0.0:8083 0.0.0.0:* LISTEN 22812/java # 关闭进程
kill 22812
在windows上部署建议创建一个bat文件,这样只要双击bat文件就可以启动了:
title XXX系统
java -jar easyweb-shiro-0.0.1.jar --spring.profiles.active=test
bat文件前面加一个title的好处是打开的命令窗口可以显示项目的名字,避免部署太多项目无法区分哪个命令窗口对应哪个项目。
windows查看端口占用及停掉端口:
netstat -ano |findstr "8081"
tskill 6124
不同域名映射到不同端口的项目:
http {server {listen 80;server_name localhost;location / {root html;index index.html index.htm;}}# 域名一server {listen 80;server_name aaa.xxx.com;location / {proxy_pass http://localhost:8081/;}}# 域名二server {listen 80;server_name bbb.xxx.com;location / {proxy_pass http://localhost:8082/;}}
}
https配置:
http {server {listen 80;server_name localhost;location / {root html;index index.html index.htm;}}# 配置http转发到httpsserver {listen 80;server_name aaa.xxx.com;rewrite ^ https://$http_host$request_uri? permanent;}# 配置httpsserver {listen 443 ssl;server_name aaa.xxx.com;# ssl证书ssl_certificate cert/xxxxxxx.pem;ssl_certificate_key cert/xxxxxxx.key;ssl_session_cache shared:SSL:1m;ssl_session_timeout 5m;ssl_ciphers HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers on;location / {proxy_pass http://localhost:8081/;}}
}
上面都是后端项目的配置,前端项目的配置:
http {server {listen 80;server_name localhost;location / {root html;index index.html index.htm;}}# 项目一server {listen 80;server_name aaa.xxx.com;location / {root C:/www/project1;index index.html index.htm;}}# 项目二server {listen 80;server_name bbb.xxx.com;location / {root C:/www/project2;index index.html index.htm;}}# 项目三http转发到httpsserver {listen 80;server_name ccc.xxx.com;rewrite ^ https://$http_host$request_uri? permanent;}# 项目三https配置server {listen 443 ssl;server_name ccc.xxx.com;# ssl证书ssl_certificate cert/xxxxxxx.pem;ssl_certificate_key cert/xxxxxxx.key;ssl_session_cache shared:SSL:1m;ssl_session_timeout 5m;ssl_ciphers HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers on;location / {root C:/www/project3;index index.html index.htm;}}
}
nginx常用命令:
# linux进入sbin下
./nginx -s reload# windows在nginx.exe目录
nginx.exe -s reload
如果修改了页面代码,需要重启服务器才能更新,对IDEA做如下设置:
按住 Shift
+Ctrl
+Alt
+/
,选择Registry;
找到compiler.automake.allow.when.app.running
并勾选;
打开file
/settings
/Compiler
,勾选Build project automatically
:
完成上面三步设置,重启服务器即可热更新,如果还不行,再做如下设置:
第一个选择Update Classes and resources
,第二个On frame deactivation:
选择Update resources
。
一般都是包名没有修改彻底,修改包名建议使用全局替换的方式,对着src目录右键:
pom.xml文件增加如下配置:
原因是maven打包会对项目进行转码,导致文件损坏,assets目录下都是静态资源,无需转码,添加上面代码排除即可。
导入后运行提示非法字符\ufeff
,一些功能提示演示系统不能操作
,修改密码提示原始密码不正确
等这些问题你需要重新下载最新的压缩包, 提示非法字符你也可以通过IDEA右下角编码切换为GBK
再切换为UTF-8
解决。