此文包含:
1、新建项目Springboot项目
2、如何返回字符串/JSON
3、添加视图支持,可以返回数据,此处使用是velocity
4、把后台数据显示在前台页面上
5、前台显示后台传递的数据
6、使用日志Logger 添加依赖
7、使用JPA(Hibernate)操作数据库
8、使用JdbcTemplates保存数据
9、security安全机制
10、拦截器配置
11、定时任务(springboot自带)
12、定时任务,使用 ScheduledExecutorService
13、定时任务 使用Timer 可以指定时间点执行
14、返回JSP页面,亲测可用
15、JSON数据处理,返回/解析
16、异常处理
17、Springboot实现分页
18、多对一和一对多关系绑定和连接查询
19、如何发布/运行项目
1、新建项目Springboot项目
新建一个maven项目即可,然后修改pom文件,添加以下依赖,是做web必须的
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId></dependency> |
新建一个Controller
@EnableAutoConfiguration //自动配置 @Controller @RequestMapping(value = "/hi") public class Application { private static final Logger logger = LoggerFactory.getLogger(Application.class);//日志 @RequestMapping(value = "/hello") @ResponseBody //返回字符,JSON等 public String hi() { System.out.print("============="); return "我是一个字符串"; } public static void main(String[] args) { SpringApplication.run(Application.class, args);//运行方式一//下面第二种运行方式 任选一种即可SpringApplication app = new SpringApplication(SpringbootMApplication.class);ApplicationContext atc = app.run(args); } } |
注:如需返回json数据,直接返回即可,会自动转化为JSON.例如:返回一个User对象,直接返回user.toString即可,返回User列表,返回类型为List<User>,直接返回list即可。Springboot会自动转化的。具体请看15,有更多演示。
3、添加视图支持,可以返回数据,此处使用是velocity
首先添加依赖;如需把数据显示在页面,使用map,model均可,下面4有具体介绍。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-velocity</artifactId></dependency> |
@RequestMapping(value = "/login", method = RequestMethod.GET) public String loginGet(String username, String password) { return "login"; } |
一般使用Map,或者Model
@RequestMapping(value = "/login", method = RequestMethod.GET) public String login(String username, String password, Map map) { map.put("username", username); Date d = new Date(); map.put("time", d.toLocaleString()); logger.info("准备转发进去");//打印日志在日志文件里 return "hi"; } |
此处使用是Velocity,具体可以参考其语法,如果是JSP,按jsp语法写
<body> hello:${username},现在时间:${time}//也可以不带{} </body> |
6、使用日志Logger 添加依赖:
<properties> <<<在这个里面添加下面的2个<log4j.version>2.5</log4j.version> <logback-classic>1.1.5</logback-classic> </properties><!--依赖里面添加 log start --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback-classic}</version> </dependency> <!-- log end --> |
logging.file=SpringBoot/src/log/app.log //我写的是项目名目录下 logging.level.org.springframework.web=DEBUG |
import org.slf4j.Logger; //是这2个包,不是阿帕奇的 import org.slf4j.LoggerFactory;private static final Logger logger = LoggerFactory.getLogger(MyApplication.class); @RequestMapping(value = "/login", method = RequestMethod.GET) public String login(String username, String password, Map map) { map.put("username", username); Date d = new Date(); map.put("time", d.toLocaleString()); logger.info("准备转发进去");//打印日志在日志文件里 return "hi"; } |
1.添加依赖,和Mysql依赖
<dependency>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> |
#数据库信息
spring.datasource.url = jdbc:mysql://localhost:3306/test spring.datasource.username = root spring.datasource.password = root spring.datasource.driverClassName = com.mysql.jdbc.Driver #数据库类型 spring.jpa.database = MYSQL #格式化sql语句 spring.jpa.show-sql = true #每次启动是更新表还是创建表 (create, create-drop, update)2个都可以用,个人感觉第二个好用 spring.jpa.hibernate.ddl-auto = update spring.jpa.properties.hibernate.hbm2ddl.auto=update spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy #数据库方言 spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect |
@Transactional
public interface UserDao extends JpaRepository<User, Long> { User findByName(String name); //解析方法名称查询 .注意JPA命名规范 @Query("from User u where u.name=:name") //支持自定义查询 User findUser(@Param("name") String name); } |
@Autowired
private UserDao userServiceImpl; List<User> users = new ArrayList<User>(); users = userServiceImpl.findAll(); |
8、使用JdbcTemplates保存数据
无需添加依赖,有上面的依赖即可。具体使用如下:
@Autowired
private JdbcTemplate JdbcTemplate; /**
*/ public void JdbcTests(User u) { String sql = "insert into User(id,name) values(?,?)"; JdbcTemplate.update(sql, u.getId(), u.getName()); } |
9、security安全机制
1.pom文件添加依赖
<dependency>
<groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> |
#安全控制
security.user.name=admin security.user.password=admin |
1.自定义一个拦截器 写一个类继承HandlerInterceptorAdapter类,重写preHandle(请求发生前执行)和postHandle(请求完成后执行)
public class inteceptor extends HandlerInterceptorAdapter {
private static Set<String> path = new HashSet<String>(); static { // 不拦截的路径 path.add("/login.vm"); path.add("/home"); } /**
*/ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long start = System.currentTimeMillis(); request.setAttribute("start", start); if (path.contains(request.getRequestURI())) { System.out.println("URL:" + request.getRequestURI()); return true; } System.out.println("----redirect"); response.sendRedirect("login.vm"); return false; } /**
*/ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { long start = (long) request.getAttribute("start"); long now = System.currentTimeMillis(); System.out.println("-----:" + (now - start)); request.setAttribute("time", new Date().toLocaleString()); } |
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter { /**
*/ @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new inteceptor());//inteceptor类是我自定义的拦截器类 System.out.println("拦截器注册完成....."); } } |
还有是java内的。只需要写一个定时任务的类,然后在方法里面启动需要执行的任务即可,一个类可以定多个定时任务
@Configuration
@EnableScheduling // 标注启动定时任务 public class SchudelTime { /**
*/ @Scheduled(cron = "0/20 * * * * ?") // 每隔20秒执行一次 public void doTask() { System.out.println("-----每隔20秒执行一次 at:" + new Date().toLocaleString()); } @Scheduled(fixedRate = 1000 * 30) // 每隔30秒执行一次 public void reportCurrentTime() { System.out.println("每隔30秒执行一次: The time is now " + new Date().toLocaleString()); } @Scheduled(fixedRate = 1000 * 60, initialDelay = 1000) // 每隔1分钟执行一次,延迟1秒执行 public void updatePayRecords() { System.out.println("每隔1分钟执行一次,延迟1秒执行: The time is now " + new Date().toLocaleString()); } } |
思路:新建一个类,在这个类的方法里创建定时任务调度器,然后使用调度器自带的方法执行具体的任务(是类,不是方法),这个类需要实现Runable接口
/** * 链接服务端接口的定时任务 * Created by server on 2016/9/2. */ public class LinkServerScheduled { public static void scheduleWithFixedDelay() { ScheduledExecutorService schedule = Executors.newScheduledThreadPool(5); //延迟10秒,以后每隔30秒执行一次 . schedule.scheduleWithFixedDelay(new UpdateTask(), 10, 30, TimeUnit.SECONDS); } // schedule不止scheduleWithFixedDelay一个方法,很多种 }下面是UpdateTask类public class UpdateTask implements Runnable { private static final Logger logger = LoggerFactory.getLogger(UpdateTask.class); @Override public void run() { System.out.println("======begin do something:--" + new Date().toLocaleString());} |
比如10点10分 写一个普通类,里面有具体执行定时任务的方法,在这个方法中new定时任务管理器,启动定时任务,设置时间。
public class TimerDemo {
public void dosomething() { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 16); // 时 calendar.set(Calendar.MINUTE, 17);// 分 calendar.set(Calendar.SECOND, 00); // 秒 Date date = calendar.getTime(); // 第一次执行定时任务的时间 // 如果第一次执行定时任务的时间 小于当前的时间 // 此时要在 第一次执行定时任务的时间加一天,以便此任务在下个时间点执行。如果不加一天,任务会立即执行。 if (date.before(new Date())) { calendar.add(Calendar.DAY_OF_MONTH, 1); date = this.addDay(date, 1); } System.out.println("exe Time:" + date.toLocaleString()); Timer timer = new Timer(); /、执行任务的调度类 TimerTask task = new TimerTask();// 具体的任务类 timer.schedule(task, date, 10000);// 任务类,第一次执行时间点,延迟时间 //timer.cancel();//取消任务 } // 增加或减少天数 public static Date addDay(Date date, int num) { Calendar startDT = Calendar.getInstance(); startDT.setTime(date); startDT.add(Calendar.DAY_OF_MONTH, num); return startDT.getTime(); } } |
public class AllFullTask extends TimerTask { private static final Logger logger = LogManager.getLogger(QueryTaskServiceImpl.class); @Override public void run() {//在这里写具体的执行逻辑 } |
注意:不能添加volecity等其他模板,把其他模板依赖去掉,1.需要在src>main目录下新建webapp>WEB-INF>jsp文件夹。注意webapp和java,resources是同一级别。2.在application.properties文件夹定义前后缀。3.添加具体的依赖
application.properties文件这样配置:
# 页面默认前缀目录
spring.mvc.view.prefix=/WEB-INF/jsp/ 响应页面默认后缀spring.mvc.view.suffix=.jsp |
<dependency> <!--JSTL支持,非必须-->
<groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency> <dependency> <!--必须--> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <!--必须--> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> <scope>provided</scope> </dependency> |
15、JSON数据处理,返回/解析
注意此处使用了net.sf.json包,需要添加依赖:需要这样写:
<dependency>
<groupId>net.sf.json-lib</groupId> <artifactId>json-lib</artifactId> <version>2.4</version> <classifier>jdk15</classifier> </dependency> |
package com.sbm.wll.controller;
import java.util.List; import java.util.Map; import org.json.JSONArray; import org.json.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.ArrayList; import java.util.HashMap; import com.sbm.wll.dao.UserDao; import com.sbm.wll.entity.User; /**
*/ @Controller public class Json { @Autowired private UserDao userServiceImpl; /**
*/ @RequestMapping(value = "/json1") @ResponseBody public String getJson1() { String str = "{"a":"b", "c":"d"}"; JSONObject obj = new JSONObject(str);// org.json System.out.println("json字符串转json:" + obj); return str; } /**
*/ @RequestMapping(value = "/json2") @ResponseBody public List<User> getJson2() { List<User> users = null; users = userServiceImpl.findAll(); // net.sf.json.JSONArray array = new // net.sf.json.JSONArray().fromObject(users); // System.out.println("-----使用.net.sf.json:"+array); net.sf.json.JSONArray as=new net.sf.json.JSONArray().fromObject(""); return users; } /**
*/ @RequestMapping(value = "/json3") @ResponseBody public String getJson3() { List<User> users = null; users = userServiceImpl.findAll(); JSONArray array = new JSONArray(); // org.json包 for (int i = 0; i < users.size(); i++) { User u = users.get(i); System.out.println("u:"+u.toString()); JSONObject object = new JSONObject(u); System.out.println("object:" + object); array.put(object); } System.out.println("org.json.Array:to json:" + array); return array.toString(); } /**
*/ @RequestMapping(value = "/json4") @ResponseBody public String getJson4() { Map<String, String> map = new HashMap<>(); map.put("1", "c100"); map.put("2", "c233"); map.put("4", "c556"); net.sf.json.JSONArray array = new net.sf.json.JSONArray().fromObject(map); System.out.println("-----使用.net.sf.json:" + array); return array.toString(); } /**
*/ @RequestMapping("/jx1") @ResponseBody public String jxJSON1() { String jsonString = "{'id':'1','corpcode':'10147','msg':{'time':'16-35','pp':'ddd'}}"; JSONObject obj = new JSONObject(jsonString); // org.json System.out.println("corpcode:" + obj.getString("corpcode")); JSONObject msg = new JSONObject(obj.get("msg").toString());// msg不是String,要么get,要么getJSONObj System.out.println("msg:" + msg); // 获取msg 里面的json内容 String time = msg.getString("time"); System.out.println("msg---time:" + time); System.out.println("全部json:" + obj); return obj.toString(); } /**
*/ @RequestMapping("/jx2") @ResponseBody public String jsJSON2() { String jString = "[{'id':'111','name':'小明'},{'id':'22','name':'小花'},{'id':'402','name':'小红'}]"; com.alibaba.fastjson.JSONArray array = new com.alibaba.fastjson.JSONArray().parseArray(jString); List<User> users = new ArrayList<>(); for (int i = 0; i < array.size(); i++) { User user = new User(); com.alibaba.fastjson.JSONObject object = array.getJSONObject(i); user.setId(Integer.valueOf(object.getString("id"))); user.setName(object.getString("name")); System.out.println("U:" + user.toString()); users.add(user); } for (User u : users) { System.out.println("----" + u.toString()); } return ""; } } |
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView;
/**
* component-scan>自动扫描到 * 它通常被用于定义 @ExceptionHandler、@InitBinder和ModelAttribute * 调用所有的被@RequestMapping标记的类之前,注解类中方法会被先执行(相当于spring的aop, * 一个过滤器) 如果没有定义需要支援的controller的范围,则默认支援所有能扫描controller */ @ControllerAdvice public class GeneraException { private static final Logger logger = LoggerFactory.getLogger(GeneraException.class);
@ExceptionHandler(value = Exception.class) public String defaultErrorHandler(HttpServletRequest req, Exception ex) { System.out.println("异常类启动....."); ModelAndView mav = new ModelAndView(); mav.addObject("exception", ex); mav.addObject("url", req.getRequestURL()); mav.setViewName("error"); logger.error("================错误位置:" + req.getRequestURI() + " \n 错误信息:" + ex); return "error"; } } |
先在实现JPA接口的接口里面写下面方法: plan 是需要分页的实体类对象
Page<Plan> findAll(Specification<Plan> specification, Pageable pageable); |
public String findall(int pageNumber, int pageSize) { // PageAble 接口通常用的是PageRequest实现类,其中封装了需要分页的信息 // 排序相关的,sor封装了排序的信息 Order order1 = new Order(Direction.ASC, "id");//升序还是降序,根据的字段 Sort sort = new Sort(order1); Pageable pageable = new PageRequest(pageNumber - 1, pageSize, sort); DataBean dataBean = new DataBean(); Specification<Plan> specification = new Specification<Plan>() { /* Plan是实体类 * @param root:代表的查询的实体类 * @param query:可以从中得到Root对象,即告知JPA Criteria查询要查询哪一个实体类, * 还可以来添加查询条件,还可以结合EntityManager对象得到最终查询的TypedQuery 对象 * cb:criteriabuildre对象,用于创建Criteria相关的对象工程,当然可以从中获取到 predicate类型 * @return:代表一个查询条件 */ @Override public Predicate toPredicate(Root<Plan> root, CriteriaQuery<?> query, CriteriaBuilder cb) { Predicate p1 = cb.equal(root.get("isexist").as(String.class), "Y"); Predicate p2 = cb.equal(root.get("corp_code").as(String.class), corp_code); // 构建组合的Predicate示例: Predicate p = cb.and(p1, p2);//查询条件 return p; } }; Page<Plan> page = planService.findAll(specification, pageable);//单独写的方法 return JSON.toJSONString(page); //直接转化为JSON返回 |
1、实体类如何绑定:例子:书和读者,一个读者读多本书,一本书可能有多个读者
//读者实体类
import java.util.HashSet; import java.util.Set; import javax.persistence.*; @Entity @Table(name = "reader") public class Reader { @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO)//int类型自增策略 private int id; //mappedBy表示拥有方 cascade维护所有,fetch为懒加载 @OneToMany(mappedBy="reader",cascade=CascadeType.ALL,fetch=FetchType.LAZY) private Set<Book> books = new HashSet<Book>(); public Set getBooks() { return books; } public void setBooks(Set books) { this.books = books; } |
import javax.persistence.*;
@Entity @Table(name = "book") public class Book { @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO)//主键生成策略 int类型 private int id; @ManyToOne(cascade = CascadeType.ALL, optional = false) @JoinColumn(name = "rea_id") // 就是在book表显示的字段名称 private Reader reader; public Reader getReader() { return reader; } public void setReader(Reader reader) { this.reader = reader; } |
具体Controller中这样写保存方法:
@Autowired
private ReaderDao readerDaoImpl; //使用JPA的 @Autowired private BookDao bookDaoImpl;//使用JPA public String addTest(HttpServletRequest request) { Reader r = new Reader();//一个读者多本书 r.setName("LIMING"); r.setMeno("man"); Book b1 = new Book(); b1.setTitle("Java"); Book b2 = new Book(); b2.setTitle("C++"); b1.setReader(r); b2.setReader(r); Set<Book> bs = new HashSet<Book>(); bs.add(b1); bs.add(b2); r.setBooks(bs); // r.getBooks().add(b1); 另一种绑定方式 // r.getBooks().add(b2);另一种绑定方式 // bookDaoImpl.save(b1); // bookDaoImpl.save(b2); // readerDaoImpl.save(r); // System.out.println("添加完成"); Book bbBook = bookDaoImpl.findById(1); request.setAttribute("b1", bbBook);//放在request中 return "book"; } |
<body>
<% Book b = (Book) request.getAttribute("b1"); %> title:<%=b.getTitle()%> ----reader:<%=b.getReader().getName() %> </body> |
19、如何发布/运行项目
如果是Velocity模板直接 mvn clean package -DskipTests 然后运行jar包即可。如果是jsp支持,在Eclipse编辑后发布项目 1.改pom文件中jar为war, cmd 进入项目目录,执行命令:mvn clean package即可生成war文件。然后直接在cmd :java -jar xxx.war即可,也可以编辑一个bat批处理,如: java -jar .\demo-0.0.1-SNAPSHOT.war 即可