热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

EASYspa后端文档

1.1.导入运行导入sql脚本到MySQL中,sql位于srcmainresourcessql中;使用IDEA打开项目,检查applic

1.1.导入运行


  1. 导入sql脚本到MySQL中,sql位于src/main/resources/sql中;
  2. 使用IDEA打开项目,检查application-dev.yml中数据库账号密码是否正确;
  3. 运行src目录下的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);

 


6.1.上传文件

框架已经内置了FileController支持上传、预览、下载、缩略图、office预览等功能。


接口参数方法说明
file/uploadfilepost上传文件
file/upload/base64base64post上传Base64文件
file/{dir}/{name}get预览文件(支持office)
file/thumbnail/{dir}/{name}get预览缩略图
file/download/{dir}/{name}get下载文件
file/listdirget查询文件列表
file/removepathdelete删除文件

前端使用示例:


上传成功返回的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中配置安装位置,也可在群里下载。

 


6.2.异步任务

异步任务需要在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");}
}

框架里面的登录日志、操作日记添加都是使用的异步任务,异步任务一般用于跟业务逻辑无关的操作, 使业务流程处理完后立即返回给前端,与业务流程无关的操作异步执行,提升业务功能的执行效率。

 


6.3.定时任务

定时任务需要在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表达式生成器

 


6.4.发送邮件

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 map = new HashMap<>(); // 页面的动态数据map.put("name", "admin");map.put("sex", "女");emailService.sendHtmlEmail("邮件标题", "sys/test.html", map, new String[]{"222222@qq.com"});}
}

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端口。

 


7.1.application.yml

application.yml是SpringBoot的核心配置文件,所有的配置都在它里面,另外还有三个是做多环境配置的:


配置文件说明
application-dev.yml开发环境配置,配置开发环境的数据源、日志处理等
application-prod.yml生成环境配置,配置生产环境的数据源、日志处理等
application-test.yml测试环境配置,配置测试环境的数据源、日志处理等

在application.yml中配置spring.profiles.active=dev来指定使用哪个环境,建议像数据库、redis、日志处理等 在不同环境中配置不一样的写在三个不同环境的配置文件中,不会随着环境改变的配置写在application.yml中。


7.2.日期转换器

日期类型转换器位于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类型是不支持的


7.3.异常处理

全局异常处理器位于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 roleIds) {boolean result = baseMapper.insert(user) > 0;if (result) {if (userRoleMapper.insertBatch(user.getUserId(), roleIds) }

上面是一个添加用户的例子,添加完用户后还要添加用户的角色,如果角色添加失败,应该回滚添加的用户,此时抛出异常才可回滚, 也别忘了加@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。


7.4.MybatisPlus配置

MybatisPlus的配置位于com.xxx.common.core.config下面,代码如下:

@Configuration
@EnableTransactionManagement
public class MybatisPlusConfig {// 分页插件@Beanpublic PaginationInterceptor paginationInterceptor() {return new PaginationInterceptor().setLimit(1000);}
}

@EnableTransactionManagement注解是开启事务,这里加了就不用在Application上加了。


7.5.Security配置

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(&#39;/login&#39;, {username: &#39;admin&#39;,password: &#39;123456&#39;
},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(&#39;/sys/user&#39;, {access_token: &#39;xxxxx&#39;
}, function(res){console.log(res);
}, &#39;json&#39;);// 在header中传递token
$.ajax({url: &#39;/sys/user&#39;, headers: { Authorization: &#39;Bearer &#39; + token },success: function(res){console.log(res);}
});

在参数中传递用access_token,在header中传递用Authorization,值前面要加Bearer,注意有个空格。

security权限注解使用:

// 一般加在controller的方法上面
@PreAuthorize("hasAuthority(&#39;sys:user:save&#39;)")

7.6.Swagger配置

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了。


7.7.resources目录

resources下的static目录用于存放静态资源,因为是前后端分离的,所以不需要templates目录,static下面的文件可以直接放到nginx中分离部署, 之所以放在static下面是为了一个人开发的方便,如果有专门的前端完全可以把static下面的文件单独作为一个前端项目,分离开发、分离部署。


7.8.集成redis

在pom.xml中增加:

org.springframework.bootspring-boot-starter-data-redis

在application.properties中配置

spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=

 


8.1.项目生成

项目生成器可以生成一个完整的项目,包括controller、service、entity、mapper、页面等,生成的功能包含添加、修改、删除、批量添加、批量修改、 批量删除、查询全部、分页查询、根据id查询,项目生成器可以自定义模板,目前提供了shiro版本的框架模板以及SpringSecurity版本的框架模板, 也可以自己制作框架模板。

项目生成器使用步骤,首先你要创建好你的数据库,数据库的字符集选utf8mb4,排序规则选utf8mb4_general_ci, 然后导入系统管理部分的sql脚本:

 

创建好数据库后再创建你的业务表,这里新增了两个表举例子,文章和评论,注意表备注后面不要带表,不然生成后的代码就是文章表管理了:

第一步配置你的数据库连接信息:

第二步选择你的表,功能比较少的项目可以不划分模块,模块名空着:

第三步配置其它信息:

配置完后点击立即生成,生成完毕会自动下载,解压下载的压缩包:

用IDEA开发工具导入项目,生成的项目结构如下:

resources\sql\目录下会有一个生成的sql脚本,是用来添加菜单和角色菜单的,你可以适当修改后导入数据库, 也可以直接导入到数据库中:

对于功能较多的项目,数据表较多的项目推荐把不同的表划分到不同的模块中,这里的模块最后生成的不是maven的多模块, 是以划分包的形式,你可以根据自己业务进行划分:

划分多模块最后生成的项目结构为:

 

生成好的项目可以直接运行,添删改查、批量添、改、删、分页查、根据id查、页面都会生成:

 


8.2.多表关联

生成的代码没有多表关联的操作,但是提供好了模板,你可以看到生成的Controller中关联的操作注释了:

/** 评论管理 */
@Controller
@RequestMapping("/model2/comment")
public class CommentController extends BaseController {@Autowiredprivate CommentService commentService;/** 分页查询评论 */@ResponseBody@RequestMapping("/page")public PageResult page(HttpServletRequest request) {PageParam pageParam = new PageParam<>(request);return new PageResult<>(commentService.page(pageParam, pageParam.getWrapper()).getRecords(), pageParam.getTotal());//return commentService.listPage(pageParam); // 使用关联查询}/** 查询全部评论 */@ResponseBody@RequestMapping("/list")public JsonResult list(HttpServletRequest request) {PageParam pageParam = new PageParam<>(request);return JsonResult.ok().setData(commentService.list(pageParam.getOrderWrapper()));//List records = commentService.listAll(pageParam.getNoPageParam()); // 使用关联查询//return JsonResult.ok().setData(pageParam.sortRecords(records));}/** 根据id查询评论 */@ResponseBody@RequestMapping("/get")public JsonResult get(Integer id) {return JsonResult.ok().setData(commentService.getById(id));// 使用关联查询//PageParam pageParam = new PageParam<>();//pageParam.put("comment_id", id);//List records = commentService.listAll(pageParam.getNoPageParam());//return JsonResult.ok().setData(pageParam.getOne(records));}
}

如果需要多表关联查询,把注释的代码放开,service不用修改,需要在mapper.xml中增加关联的sql语句,模板会生成好sql语句, 你只需要在原来的语句上面增加LEFT JOIN语句去关联表即可:

SELECT a.*, b.titleFROM tb_comment aLEFT JOIN tb_blog b ON a.blog_id = b.blog_idAND a.comment_id = #{page.pageData.commentId}AND a.blog_id = #{page.pageData.blogId}AND a.user_name LIKE CONCAT(&#39;%&#39;, #{page.pageData.userName}, &#39;%&#39;)AND a.content LIKE CONCAT(&#39;%&#39;, #{page.pageData.content}, &#39;%&#39;)AND a.deleted = #{page.pageData.deleted}AND a.deleted = 0AND a.create_time >= #{page.pageData.createTimeStart}AND a.create_time <= #{page.pageData.createTimeEnd}AND b.title LIKE CONCAT(&#39;%&#39;, #{page.pageData.title}, &#39;%&#39;)

上面的例子就是在评论表中把对应文章的标题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数据里面就会有这个关联的字段了。

 


8.3.模板制作

一套完整的模板应该包含:


名称类型说明
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可以配置三个属性:


  • packageName 基础框架的原始包名
  • pages 配置页面生成模板,不要页面可以配置为pages: []
  • replaces 配置需要修改基础框架的内容

pages是一个数组,可以配置多个,tpl是模板的名称,output是模板输出位置。

replaces也是一个数组,里面的files是需要修改基础框架的文件,items是需要修改的内容, orgStr是需要修改的原始内容,newStr是替换的内容,newStr可以使用${}语法获取一些模板数据。

newStr可以获取的数据:


数据描述
projectName生成的项目名称
groupId生成的项目的groupId
groupIdPathgroupId的点变成斜杠形式
packageName生成的项目的包名
packageNamePath包名的点变成斜杠形式
author作者的名称
dbUrl数据库的url
dbUserName数据库的账号
dbPassword数据库的密码
dbDriverName数据库的驱动名

其他模板可以取的数据:


  • author   作者名称
  • package   包相关数据
  • table   表数据
  • cfg   项目生成器相关的数据
    • genConfig   项目配置
      • dbUrl   数据库连接地址
      • dbUserName   数据库连接账号
      • dbPassword   数据库连接密码
      • dbDriverName   数据库连接驱动
      • projectName   项目名称
      • groupId
      • packageName   包名
      • tplName   使用模板名称
      • needPerm   是否需要权限注解
      • needLog   是否需要日志注解
      • menuStartId   菜单起始id
    • genModel   当前模块
      • modelName   模块名称
      • tables   模块下所有的表名(集合)
      • prefix   模块下所有表前缀(集合)
    • genDateTime   当前时间
    • genModelList   所有模块信息(集合)

制作好的模板压缩并上传到项目生成器中就可以使用了:

提示 如果上传失败请自己把压缩包放在C:\easyweb-generator\tpl目录下面

 


8.4.注意事项


  • 逻辑删除字段名必须为deleted
  • 数据库是下划线形式,实体类是驼峰形式 (固定的配置)
  • 数据库表的名称(表备注)不要带
  • 创建时间字段建议为create_time (模板会对表单过滤此字段)
  • 修改时间字段建议为update_time (模板会对表单过滤此字段)
  • 只能生成单体单模块项目,制作模板不要用多模块项目

当然你可以修改项目生成器源码满足更多的配置。

 

 


9.1.上传文件实例

代码示例:



9.2.表单中上传文件

完整代码:


建议表单内上传文件像上面这样,先上传获取url,提交表单时只是把上传后的url提交,而不是传统的表单提交又有文件、 又有其他参数,当然这样做会存在文件上传了,表单不提交导致的垃圾文件的问题,这个问题可以通过定时清理很久没有使用的文件来解决。


9.3.刷新token实例

在setter.js的ajaxSuccessBefore中判断服务器的response的header中是否有Authorization字段,有就表示token马上要过期了, 服务端生成了新的token,前端需要把新的token存起来:

layui.define([&#39;table&#39;], function (exports) {var setter = {/* ajax请求结束后的处理 */ajaxSuccessBefore: function (res, url, obj) {// 判断response是否有tokenvar newToken = obj.xhr.getResponseHeader(&#39;Authorization&#39;);if (newToken) setter.putToken({access_token: newToken});// ......其他代码省略return true;}};exports(&#39;setter&#39;, setter);
});

或者使用ajaxSetup实现,这个对table的请求也有用:

// ajax统一处理
$.ajaxSetup({complete: function (xhr) {var newToken = xhr.getResponseHeader(&#39;Authorization&#39;);if (newToken) setter.putToken({access_token: newToken});}
});

 

 


10.1.使用IDEA打包

点击右侧的Maven/package即可开始打包,打好的包在target下面:


10.2.部署到Linux

先把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

10.3.部署到Windows

在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

10.4.nginx的使用

不同域名映射到不同端口的项目:

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

 

 


11.1.IDEA热更新

如果修改了页面代码,需要重启服务器才能更新,对IDEA做如下设置:


  1. 按住 Shift+Ctrl+Alt+/,选择Registry;

  2. 找到compiler.automake.allow.when.app.running并勾选;

  3.  

  4. 打开file/settings/Compiler,勾选Build project automatically

  5.  

完成上面三步设置,重启服务器即可热更新,如果还不行,再做如下设置:

第一个选择Update Classes and resources,第二个On frame deactivation:选择Update resources

 


11.2.修改包名后无法运行

一般都是包名没有修改彻底,修改包名建议使用全局替换的方式,对着src目录右键:

 

 


11.3.部署后字体图标不显示

pom.xml文件增加如下配置:

org.springframework.bootspring-boot-maven-pluginsrc/main/resourcestrue**/assets/**src/main/resourcesfalse**/assets/**

原因是maven打包会对项目进行转码,导致文件损坏,assets目录下都是静态资源,无需转码,添加上面代码排除即可。

 


11.4.导入后提示非法字符

导入后运行提示非法字符\ufeff,一些功能提示演示系统不能操作,修改密码提示原始密码不正确等这些问题你需要重新下载最新的压缩包, 提示非法字符你也可以通过IDEA右下角编码切换为GBK再切换为UTF-8解决。

 


推荐阅读
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 本文介绍了如何使用C#制作Java+Mysql+Tomcat环境安装程序,实现一键式安装。通过将JDK、Mysql、Tomcat三者制作成一个安装包,解决了客户在安装软件时的复杂配置和繁琐问题,便于管理软件版本和系统集成。具体步骤包括配置JDK环境变量和安装Mysql服务,其中使用了MySQL Server 5.5社区版和my.ini文件。安装方法为通过命令行将目录转到mysql的bin目录下,执行mysqld --install MySQL5命令。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文讨论了微软的STL容器类是否线程安全。根据MSDN的回答,STL容器类包括vector、deque、list、queue、stack、priority_queue、valarray、map、hash_map、multimap、hash_multimap、set、hash_set、multiset、hash_multiset、basic_string和bitset。对于单个对象来说,多个线程同时读取是安全的。但如果一个线程正在写入一个对象,那么所有的读写操作都需要进行同步。 ... [详细]
author-avatar
手机用户2602910773
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有