热门标签 | 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解决。

 


推荐阅读
  • 本文介绍如何使用 Python 的 DOM 和 SAX 方法解析 XML 文件,并通过示例展示了如何动态创建数据库表和处理大量数据的实时插入。 ... [详细]
  • 本文介绍了如何在 Spring 3.0.5 中使用 JdbcTemplate 插入数据并获取 MySQL 表中的自增主键。 ... [详细]
  • MySQL 5.7 学习指南:SQLyog 中的主键、列属性和数据类型
    本文介绍了 MySQL 5.7 中主键(Primary Key)和自增(Auto-Increment)的概念,以及如何在 SQLyog 中设置这些属性。同时,还探讨了数据类型的分类和选择,以及列属性的设置方法。 ... [详细]
  • 本教程详细介绍了如何使用 Spring Boot 创建一个简单的 Hello World 应用程序。适合初学者快速上手。 ... [详细]
  • php更新数据库字段的函数是,php更新数据库字段的函数是 ... [详细]
  • 属性类 `Properties` 是 `Hashtable` 类的子类,用于存储键值对形式的数据。该类在 Java 中广泛应用于配置文件的读取与写入,支持字符串类型的键和值。通过 `Properties` 类,开发者可以方便地进行配置信息的管理,确保应用程序的灵活性和可维护性。此外,`Properties` 类还提供了加载和保存属性文件的方法,使其在实际开发中具有较高的实用价值。 ... [详细]
  • Hadoop的文件操作位于包org.apache.hadoop.fs里面,能够进行新建、删除、修改等操作。比较重要的几个类:(1)Configurati ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • 本文介绍了在 Spring Boot 中使用 JPA 进行数据删除操作时遇到的 SQL 错误及其解决方法。错误表现为:删除操作失败,原因是无法打开 JPA EntityManager 以进行事务处理。 ... [详细]
  • 本文详细介绍了 PHP 中对象的生命周期、内存管理和魔术方法的使用,包括对象的自动销毁、析构函数的作用以及各种魔术方法的具体应用场景。 ... [详细]
  • 本文详细介绍了MySQL数据库的基础语法与核心操作,涵盖从基础概念到具体应用的多个方面。首先,文章从基础知识入手,逐步深入到创建和修改数据表的操作。接着,详细讲解了如何进行数据的插入、更新与删除。在查询部分,不仅介绍了DISTINCT和LIMIT的使用方法,还探讨了排序、过滤和通配符的应用。此外,文章还涵盖了计算字段以及多种函数的使用,包括文本处理、日期和时间处理及数值处理等。通过这些内容,读者可以全面掌握MySQL数据库的核心操作技巧。 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 在JUnit测试框架中,确保@Test注解的方法按特定顺序执行是常见的需求。本文总结了三种实现这一目标的策略。首先,介绍了通过方法名称排序来控制执行顺序的基本方法。其次,推荐了一种利用依赖管理插件的方式,这种方法更为灵活且易于维护。最后,探讨了使用第三方库如TestNG或Jupiter扩展来实现更复杂的顺序控制。每种方法都有其适用场景和优缺点,开发者可以根据具体需求选择最合适的方案。 ... [详细]
  • 2.2 组件间父子通信机制详解
    2.2 组件间父子通信机制详解 ... [详细]
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社区 版权所有