angularjs java mysql_AngularJS通过HTTP与后台API进行数据交互

本文详细介绍了如何使用AngularJS通过HTTP与后端API进行数据交互,包括搭建前端架构、设置Express服务器、创建数据传输表单、解决跨域问题以及从后台读取数据并展示在图表上。主要涉及的技术栈有AngularJS、NodeJS、Express、SpringBoot和MySQL。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文实现了独立前端通过angularJS的controller向后端发送数据和从后端获取数据

搭建基础前端架构

用NodeJS搭建服务器,基础教程看这里

1. 项目架构

44f143b96b7b

Project Structure

node_modules:项目依赖的NodeJS libraries,通过npm下载,package.json和package-lock.json是其附属产物

pde_server.js:前端服务器

project_name/templates:页面源码

project_name/static:静态资源,JavaScript,CSS等

2. 添加依赖

如果没有,则在当前目录添加express library

$ cnpm install express --save

3. 修改之前的server.js成pde_server.js

1. 增加到不同文件夹的快捷路径

app.use('/js', express.static('Pennsylvania_Education/static/js'));

app.use('/css', express.static('Pennsylvania_Education/static/css'));

app.use可以用来重设静态资源的地址,当视图(html)中出现

服务器会自动查找向当前文件夹下的Pennsylvania_Education/static/css/dashboard.css

除了可以少打写字,这个功能还可以方便我们在不同的服务器下反复使用已经编写好的前端代码,比如现在这个project还可以被python的flask和SpringBoot的Thymeleaf无缝兼容,因为他们都默认进入templates文件夹查找视图,进入static文件夹查找静态资源

2. 增加到获得数据和展示数据的前台页面的路径

app.get('/applicationForm', function (req, res) {

res.sendFile( __dirname + "/Pennsylvania_Education/templates/" + "applicationForm.html" );

});

app.get('/dashBoard', function (req, res) {

res.sendFile( __dirname + "/Pennsylvania_Education/templates/" + "dashboard.html" );

});

4. 完整的pde_server.js放一份

var express = require('express');

function startServer() {

var app = express();

// use 'http://0.0.0.0:8081/static' points to local '/frontend/static'

// first parameter the same as the one include in html

app.use('/js', express.static('Pennsylvania_Education/static/js'));

app.use('/css', express.static('Pennsylvania_Education/static/css'));

app.set('view engine', 'html');

app.get('/index', function (req, res) {

res.sendFile( __dirname + "/Pennsylvania_Education/templates/" + "index.html" );

});

app.get('/applicationForm', function (req, res) {

res.sendFile( __dirname + "/Pennsylvania_Education/templates/" + "applicationForm.html" );

});

app.get('/dashBoard', function (req, res) {

res.sendFile( __dirname + "/Pennsylvania_Education/templates/" + "dashboard.html" );

});

var server = app.listen(6060, '0.0.0.0', function () {

var host = server.address().address

var port = server.address().port

console.log("visit http://%s:%s", host, port)

});

};

startServer();

向后台传输数据

1. 创建页面

templates里新建一个输入数据的表单页面applicationForm.html

AngularJS的controller中目前实现了两个方法:

scope.submitForm目前将我们输入的值返回显示在页面上,之后我们将改变这个方法使其将值传入后端

scope.transform帮助我们将选择的日期返回显示在选择框内,单纯的时间戳并没有办法显示在input内

Application Form

Application Form

First Name

Last Name

Date of Birth

submit

{{result}}

var app = angular.module('myApp', []);

app.controller('formCtrl', function($scope) {

$scope.submitForm = function () {

console.log('enter submitForm');

$scope.result = angular.copy($scope.user);

};

$scope.transform = function (transTime) {

var date = new Date(transTime);

var year = date.getFullYear();

var month = date.getMonth() + 1;

month = month < 10 ? '0' + month : month;

var d = date.getDate() < 10 ? '0' + date.getDate() : date.getDate();

return year + '-' + month + '-' + d;

};

});

44f143b96b7b

applicationForm.html

2. 使用angularJS向后端发送HTTP request

修改$scope.submitForm方法

$scope.submitForm = function () {

console.log('enter submitForm');

$http({

method:'post',

url:'http://localhost:6050/user/add',

data:$.param($scope.user),

}).then(function(resp){

console.log('post success');

console.log(resp);

},function(resp){

console.log('post error');

console.log(resp);

});

console.log('exit submitForm');

};

后台SpringBoot controller里的接收方法

@RequestMapping(value="/add", method=RequestMethod.POST)

@ApiOperation("Add User")

public void add(User u){

System.out.println(u);

userRepository.save(u);

}

运行后报如下错误

44f143b96b7b

applicationForm.html

说明请求的接口地址和本身的服务器不属于一个域内,需要设置跨区域访问。

按照报错提示给angularJS的HTTP Request添加header

$http({

method:'post',

url:'http://localhost:6050/user/add',

data:$.param($scope.user),

headers: {

'Access-Control-Allow-Origin': '*'

}

}).then......

重启后发现还是没有解决问题。调查了一下发现原来是后端Controller也要加上@CrossOrigin注释。(PS:后来测试其实只要后端有注释,前端没有Access-Control-Allow-Origin也是可以的。)

@CrossOrigin

@RestController

@Api(tags = "User internface")

@RequestMapping(value="/user")

public class UserController {

............

}

再重启之后,提交一个表单,从前端来看是成功的

44f143b96b7b

applicationForm.html

然而后端接收到的数据却没有值

2020-05-22 13:54:29.016 INFO 72808 --- [nio-6050-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'

2020-05-22 13:54:29.017 INFO 72808 --- [nio-6050-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started

2020-05-22 13:54:29.036 INFO 72808 --- [nio-6050-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 19 ms

User [ Id = 0, firstName = , lastName = , birthDate = 2020-05-22 ]

Hibernate: insert into testu (birth_date, first_name, last_name) values (?, ?, ?)

原因是默认情况下,jQuery传输数据使用Content-Type: x-www-form-urlencodedand和类似于"name=zhangsan&age=18"的序列,然而AngularJS,传输数据使用Content-Type: application/json和{ "name": "zhangsan", "age": "18" }这样的json序列。

查看Request信息,果然如此。

44f143b96b7b

Request Information

注意Content Type和Request Payload。

我们此时需要改变Request header中的Content Type。

$scope.submitForm = function () {

console.log('enter submitForm');

$http({

method:'post',

url:'http://localhost:6050/user/add',

data:$.param($scope.user),

headers: {

'Content-Type': 'application/x-www-form-urlencoded',

'Access-Control-Allow-Origin': '*'

}

}).then(function(resp){

console.log('post success');

console.log(resp);

},function(resp){

console.log('post error');

console.log(resp);

});

console.log('exit submitForm');

};

重新提交表单,得到正确结果。

2020-05-23 00:39:03.237 INFO 72808 --- [nio-6050-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet'

2020-05-23 00:39:03.237 INFO 72808 --- [nio-6050-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started

2020-05-23 00:39:03.241 INFO 72808 --- [nio-6050-exec-1] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 4 ms

User [ Id = 0, firstName = Hermione, lastName = Granger, birthDate = 2014-02-26 ]

Hibernate: insert into testu (birth_date, first_name, last_name) values (?, ?, ?)

id=0说明未给id赋值,存入MySQL时将会被自动修正为自增值。

此时的Request信息。

44f143b96b7b

Request Information

从后台读取数据

1. 检查后台方法

JPA Repository里

@Query(value = "SELECT YEAR(birth_date) AS year, COUNT(id) as num FROM testu GROUP BY YEAR(birth_date)", nativeQuery = true)

List countByBirthYear();

SpringBoot Controller里

@ResponseBody

@RequestMapping(value="/countByBirthYear", method=RequestMethod.POST)

@ApiOperation("Return the number of users born in each year")

public Map countByBirthYear(){

List summary = userRepository.countByBirthYear();

Map res = new HashMap<>();

for(int i = 0; i

Object[] ans = summary.get(i);

String year = ans[0].toString();

int count = Integer.parseInt(ans[1].toString());

res.put(year, count);

}

return res;

}

可以通过swagger-ui检测运行。

44f143b96b7b

Swagger-UI countByBirthYear

2. 创建页面

templates里新建一个显示图表的页面dashboard.html。

先设定基本的HTML架构,canvas是用来存放图表的容器。其下方的两行列表是AngularJS module中稍后会设置的两个变量,用来检验我们输出的数据是否正确。

DashBoard

Show my data summary

{{drawChart()}}

  • {{labels}}
  • {{counts}}

在static/css里创建一个dashboard.css(也可以不加并删除dashboard.html里的css依赖)

h2{

font-size:3em;

text-align:center;

font-family: Monospace;

color: #F08080;

}

#Dashboard{

width: 90%;

height: 100%;

vertical-align: middle;

margin-left: 30px;

}

#year_count{

margin: 10px 10px 10px 10px;

}

为了保证项目的结构性,每个AngularJS module都要有自己独立的区域。我们在js目录里建立当前管理当前页面的AngularJS module的app文件夹,在文件夹里创建三个js文件。

app.js: 导入当前AngularJS module。

services.js: 当前AngularJS module的controllers里注入的services。目前我们有两个方法。一个用来从后端获取数据,一个用来将数据展示到图表里。

controllers.js: 当前AngularJS module的controllers。

44f143b96b7b

js目录中的结构

app.js里就一行code。

//variable can only be defined once

var app = angular.module('myApp', []);

services.js里先创建一个用于获取数据的service,目前只有静态数据。存储数据的变量是私有的,需要公有的方法使controller可以获取其中数据。如果使变量公有,则每次在service内部使用都要用this.variableName的形式去调用,不如直接封装方便。

app.service('dataGenerator', function ($http, $q) {

var labels = ["supermarket", "clothes", "electronic", "kitchen", "baby", "book"];

var counts = [40, 100, 20, 60, 0, 30];

//private variables and functions are decorated by var

//public variables and functions are decorated by this.variableName

this.getLabels = function(){

return labels;

}

this.getCounts = function(){

return counts;

}

});

services.js里再创建一个画图的service,用获取的数据作为公有方法的input。

app.service('drawer', function () {

this.drawChart = function(labels, counts){

console.log("Enter draw chart");

var chart = document.getElementById('year_count').getContext('2d');

myChart = new Chart(chart, {

type: 'bar',

data: {

labels: labels,

datasets: [{

label: 'times of visit',

data: counts,

backgroundColor: [

'rgba(255, 99, 132, 0.2)',

'rgba(54, 162, 235, 0.2)',

'rgba(255, 206, 86, 0.2)',

'rgba(75, 192, 192, 0.2)',

'rgba(153, 102, 255, 0.2)',

'rgba(255, 159, 64, 0.2)'

],

barPercentage: 0.5

}]

}

});

console.log("Exit draw chart");

}

});

在controllers.js:里调用两个services。

app.controller('graphCtrl', function($scope, dataGenerator, drawer) {

$scope.labels = dataGenerator.getLabels();

$scope.counts = dataGenerator.getCounts();

drawer.drawChart($scope.labels, $scope.counts);

});

dashboard.html的body最下方导入三个js文件。注意顺序,比如要先创造了module,才能在其中创造服务并注入控制器。

............

44f143b96b7b

dashboard.html

3. 使用HTTP从后台获取数据

在services.js里的dataGenerator里添加一个getData()获取数据的方法。从后端获取的数据会存储到私有变量中,并且在回调函数中返回。如果请求发生错误,错误信息一样会被回调函数返回。

$http调用了官方的http请求函数,$q调用了官方的Promise回调库。

this.getData = function(){

console.log('Enter getData');

var defer = $q.defer();

//from angularJS 1.6 on, use "then" instead of "success" to get a promise manner

$http({

method:'post',

url:'http://localhost:6050/user/countByBirthYear',

headers: {

'Content-Type': 'application/x-www-form-urlencoded'

},

}).then(function(resp){

console.log('get count data successfully');

// console.log(resp);

labels = [];

counts = [];

angular.forEach(resp.data, function (v, k) {

labels.push(k);

counts.push(v);

});

defer.resolve({"labels":labels, "counts":counts});

// defer.resolve(); 如果不想返回任何结果也可以为空

},function(resp){

console.log('get count data failed');

defer.reject(resp);

});

console.log('Exit getData');

return defer.promise;

}

controller.js调用getData(),并在成功后画图。

app.controller('graphCtrl', function($scope, dataGenerator, drawer) {

dataGenerator.getData().then(function(data){

$scope.labels = dataGenerator.getLabels();

$scope.counts = dataGenerator.getCounts();

// 使用以下是一样的效果

// $scope.labels = data.labels;

// $scope.counts = data.counts;

drawer.drawChart($scope.labels, $scope.counts);

},function(err){

console.log(err);

})

});

刷新页面测试一下。

44f143b96b7b

dashboard.html

是图表坐标的问题,在图表设置中加上y轴范围的限制。

myChart = new Chart(chart, {

type: 'bar',

data: {

labels: labels,

datasets: [{

label: 'times of visit',

data: counts,

backgroundColor: [

'rgba(255, 99, 132, 0.2)',

'rgba(54, 162, 235, 0.2)',

'rgba(255, 206, 86, 0.2)',

'rgba(75, 192, 192, 0.2)',

'rgba(153, 102, 255, 0.2)',

'rgba(255, 159, 64, 0.2)'

],

barPercentage: 0.5

}]

},

options: {

scales: {

yAxes: [{

ticks: {

min: 0,

max: 5

}

}]

}

}

});

再来刷新一下,就正确了。

44f143b96b7b

dashboard.html

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值